Browse Source

fix:数据

super-yimizi 3 weeks ago
parent
commit
dc68dfbf31

+ 156 - 152
application/admin/controller/BodyTypeConfig.php

@@ -5,61 +5,59 @@ namespace app\admin\controller;
 use app\common\controller\Backend;
 use app\common\model\BodyTypeConfig as BodyTypeConfigModel;
 use think\Db;
+use think\exception\PDOException;
+use think\exception\ValidateException;
 
 /**
  * 身体类型配置管理
+ *
+ * @icon   fa fa-user-md
+ * @remark 身体类型配置管理,支持按性别分类管理身体类型
  */
 class BodyTypeConfig extends Backend
 {
+    /**
+     * BodyTypeConfig模型对象
+     * @var \app\common\model\BodyTypeConfig
+     */
     protected $model = null;
+    
+    /**
+     * 无需登录的方法
+     */
     protected $noNeedLogin = [];
+    
+    /**
+     * 无需鉴权的方法
+     */
     protected $noNeedRight = [];
+    
+    /**
+     * 快速搜索字段
+     */
     protected $searchFields = 'type_name,description';
+    
+    /**
+     * 是否开启模型验证
+     */
+    protected $modelValidate = false;
+    
+    /**
+     * 是否开启模型场景验证
+     */
+    protected $modelSceneValidate = false;
+    
+    /**
+     * Multi方法可批量修改的字段
+     */
+    protected $multiFields = 'status';
 
     public function _initialize()
     {
         parent::_initialize();
         $this->model = new BodyTypeConfigModel;
-    }
-
-    /**
-     * 查看列表
-     */
-    public function index()
-    {
-        if ($this->request->isAjax()) {
-            // 分页参数
-            $page = $this->request->get('page/d', 1);
-            $limit = $this->request->get('limit/d', 10);
-            $search = $this->request->get('search', '');
-            $type_category = $this->request->get('type_category', '');
-            $gender = $this->request->get('gender', '');
-
-            $where = [];
-            
-            // 搜索条件
-            if ($search) {
-                $where[] = ['type_name|description', 'like', '%' . $search . '%'];
-            }
-            
-            if ($type_category !== '') {
-                $where[] = ['type_category', '=', $type_category];
-            }
-            
-            if ($gender !== '') {
-                $where[] = ['gender', '=', $gender];
-            }
-
-            // 查询数据
-            $list = $this->model
-                ->where($where)
-                ->order('type_category ASC, sort ASC, id ASC')
-                ->paginate($limit);
-
-            return json(['code' => 0, 'msg' => '', 'count' => $list->total(), 'data' => $list->items()]);
-        }
-
-        // 获取分类选项
+        
+        // 分类选项
         $categories = [
             'shoulder' => '肩型',
             'chest' => '胸型(男)',
@@ -68,29 +66,55 @@ class BodyTypeConfig extends Backend
             'hip' => '臀型',
             'leg' => '腿型'
         ];
+        
+        $this->view->assign('categories', $categories);
+        $this->assignconfig('categories', $categories);
+    }
 
-        $this->assign('categories', $categories);
-        return $this->view->fetch();
+    /**
+     * 默认生成的控制器所继承的父类中有index/add/edit/del/multi五个基础方法、destroy/restore/recyclebin三个回收站方法
+     * 因此在当前控制器中可不用编写增删改查的代码,除非需要自己控制这部分逻辑
+     * 需要将application/admin/library/traits/Backend.php中对应的方法复制到当前控制器,然后进行修改
+     */
+
+    /**
+     * 查看
+     */
+    public function index()
+    {
+        //设置过滤方法
+        $this->request->filter(['strip_tags', 'trim']);
+        if (false === $this->request->isAjax()) {
+            return $this->view->fetch();
+        }
+        //如果发送的来源是 Selectpage,则转发到 Selectpage
+        if ($this->request->request('keyField')) {
+            return $this->selectpage();
+        }
+        [$where, $sort, $order, $offset, $limit] = $this->buildparams();
+        $list = $this->model
+            ->where($where)
+            ->order($sort, $order)
+            ->paginate($limit);
+        $result = ['total' => $list->total(), 'rows' => $list->items()];
+        return json($result);
     }
 
     /**
-     * 添加体型配置
+     * 添加
      */
     public function add()
     {
-        if ($this->request->isPost()) {
-            $params = $this->request->post('row/a');
-            
-            if (empty($params)) {
-                $this->error(__('Parameter %s can not be empty', ''));
-            }
-
-            // 验证必填字段
-            if (empty($params['type_category']) || empty($params['type_name'])) {
-                $this->error('分类和名称不能为空');
-            }
+        if (false === $this->request->isPost()) {
+            return $this->view->fetch();
+        }
+        $params = $this->request->post('row/a');
+        if (empty($params)) {
+            $this->error(__('Parameter %s can not be empty', ''));
+        }
 
-            // 检查是否重复
+        // 检查是否重复
+        if (!empty($params['type_category']) && !empty($params['type_name'])) {
             $exists = $this->model->where([
                 'type_category' => $params['type_category'],
                 'type_name' => $params['type_name'],
@@ -100,39 +124,31 @@ class BodyTypeConfig extends Backend
             if ($exists) {
                 $this->error('该体型配置已存在');
             }
+        }
 
-            Db::startTrans();
-            try {
-                $result = $this->model->save($params);
-                if ($result === false) {
-                    throw new \Exception($this->model->getError());
-                }
-
-                Db::commit();
-            } catch (\Throwable $e) {
-                Db::rollback();
-                $this->error($e->getMessage());
+        $result = false;
+        Db::startTrans();
+        try {
+            //是否采用模型验证
+            if ($this->modelValidate) {
+                $name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
+                $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate;
+                $this->model->validateFailException()->validate($validate);
             }
-
-            $this->success();
+            $result = $this->model->allowField(true)->save($params);
+            Db::commit();
+        } catch (ValidateException|PDOException|\Exception $e) {
+            Db::rollback();
+            $this->error($e->getMessage());
         }
-
-        // 分类选项
-        $categories = [
-            'shoulder' => '肩型',
-            'chest' => '胸型(男)',
-            'bust' => '胸型(女)',
-            'waist' => '腰型',
-            'hip' => '臀型',
-            'leg' => '腿型'
-        ];
-
-        $this->assign('categories', $categories);
-        return $this->view->fetch();
+        if ($result === false) {
+            $this->error(__('No rows were inserted'));
+        }
+        $this->success();
     }
 
     /**
-     * 编辑体型配置
+     * 编辑
      */
     public function edit($ids = null)
     {
@@ -140,15 +156,17 @@ class BodyTypeConfig extends Backend
         if (!$row) {
             $this->error(__('No Results were found'));
         }
+        if (false === $this->request->isPost()) {
+            $this->view->assign('row', $row);
+            return $this->view->fetch();
+        }
+        $params = $this->request->post('row/a');
+        if (empty($params)) {
+            $this->error(__('Parameter %s can not be empty', ''));
+        }
 
-        if ($this->request->isPost()) {
-            $params = $this->request->post('row/a');
-            
-            if (empty($params)) {
-                $this->error(__('Parameter %s can not be empty', ''));
-            }
-
-            // 检查是否重复(排除自己)
+        // 检查是否重复(排除自己)
+        if (!empty($params['type_category']) && !empty($params['type_name'])) {
             $exists = $this->model->where([
                 'type_category' => $params['type_category'],
                 'type_name' => $params['type_name'],
@@ -158,56 +176,45 @@ class BodyTypeConfig extends Backend
             if ($exists) {
                 $this->error('该体型配置已存在');
             }
+        }
 
-            Db::startTrans();
-            try {
-                $result = $row->save($params);
-                if ($result === false) {
-                    throw new \Exception($row->getError());
-                }
-
-                Db::commit();
-            } catch (\Throwable $e) {
-                Db::rollback();
-                $this->error($e->getMessage());
+        $result = false;
+        Db::startTrans();
+        try {
+            //是否采用模型验证
+            if ($this->modelValidate) {
+                $name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
+                $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : $name) : $this->modelValidate;
+                $row->validateFailException()->validate($validate);
             }
-
-            $this->success();
+            $result = $row->allowField(true)->save($params);
+            Db::commit();
+        } catch (ValidateException|PDOException|\Exception $e) {
+            Db::rollback();
+            $this->error($e->getMessage());
         }
-
-        // 分类选项
-        $categories = [
-            'shoulder' => '肩型',
-            'chest' => '胸型(男)',
-            'bust' => '胸型(女)',
-            'waist' => '腰型',
-            'hip' => '臀型',
-            'leg' => '腿型'
-        ];
-
-        $this->assign('categories', $categories);
-        $this->assign('row', $row);
-        return $this->view->fetch();
+        if (false === $result) {
+            $this->error(__('No rows were updated'));
+        }
+        $this->success();
     }
 
     /**
-     * 删除体型配置
+     * 删除
      */
     public function del($ids = null)
     {
-        if (!$this->request->isPost()) {
+        if (false === $this->request->isPost()) {
             $this->error(__("Invalid parameters"));
         }
-
-        $ids = $ids ? $ids : $this->request->post("ids");
+        $ids = $ids ?: $this->request->post("ids");
         if (empty($ids)) {
             $this->error(__('Parameter %s can not be empty', 'ids'));
         }
-
         $pk = $this->model->getPk();
         $list = $this->model->where($pk, 'in', $ids)->select();
-        $count = 0;
 
+        $count = 0;
         Db::startTrans();
         try {
             foreach ($list as $item) {
@@ -216,59 +223,56 @@ class BodyTypeConfig extends Backend
                 if ($used > 0) {
                     throw new \Exception("体型「{$item->type_name}」已被用户选择,无法删除");
                 }
-                
                 $count += $item->delete();
             }
             Db::commit();
-        } catch (\Throwable $e) {
+        } catch (PDOException|\Exception $e) {
             Db::rollback();
             $this->error($e->getMessage());
         }
-
-        $this->success();
+        if ($count) {
+            $this->success();
+        }
+        $this->error(__('No rows were deleted'));
     }
 
     /**
-     * 批量修改状态
+     * 批量更新
      */
     public function multi($ids = null)
     {
-        if (!$this->request->isPost()) {
-            $this->error(__("Invalid parameters"));
+        if (false === $this->request->isPost()) {
+            $this->error(__('Invalid parameters'));
         }
-
-        $ids = $ids ? $ids : $this->request->post("ids");
-        $action = $this->request->post("action", '');
-
-        if (empty($ids) || empty($action)) {
-            $this->error(__('Parameter %s can not be empty', 'ids/action'));
+        $ids = $ids ?: $this->request->post('ids');
+        if (empty($ids)) {
+            $this->error(__('Parameter %s can not be empty', 'ids'));
         }
 
-        $list = $this->model->where('id', 'in', $ids)->select();
+        if (false === $this->request->has('params')) {
+            $this->error(__('No rows were updated'));
+        }
+        parse_str($this->request->post('params'), $values);
+        $values = $this->auth->isSuperAdmin() ? $values : array_intersect_key($values, array_flip(is_array($this->multiFields) ? $this->multiFields : explode(',', $this->multiFields)));
+        if (empty($values)) {
+            $this->error(__('You have no permission'));
+        }
         $count = 0;
-
         Db::startTrans();
         try {
+            $list = $this->model->where($this->model->getPk(), 'in', $ids)->select();
             foreach ($list as $item) {
-                switch ($action) {
-                    case 'enable':
-                        $item->status = 1;
-                        break;
-                    case 'disable':
-                        $item->status = 0;
-                        break;
-                    default:
-                        break;
-                }
-                $count += $item->save();
+                $count += $item->allowField(true)->isUpdate(true)->save($values);
             }
             Db::commit();
-        } catch (\Throwable $e) {
+        } catch (PDOException|\Exception $e) {
             Db::rollback();
             $this->error($e->getMessage());
         }
-
-        $this->success();
+        if ($count) {
+            $this->success();
+        }
+        $this->error(__('No rows were updated'));
     }
 
     /**

+ 3 - 1
application/admin/controller/Version.php

@@ -6,7 +6,7 @@ use app\common\controller\Backend;
 
 use think\Controller;
 use think\Request;
-
+use app\common\Enum\ChannelEnum;
 /**
  * 版本管理
  *
@@ -21,6 +21,8 @@ class Version extends Backend
     {
         parent::_initialize();
         $this->model = model('Version');
+        $this->view->assign("platformList", ChannelEnum::getChannelMap());
+        $this->assignconfig("platformList", json_encode(ChannelEnum::getChannelMap()));
     }
     
 }

+ 54 - 0
application/admin/lang/zh-cn/body_type_config.php

@@ -0,0 +1,54 @@
+<?php
+
+return [
+    'Id'                    => 'ID',
+    'Type category'         => '类型分类',
+    'Type name'             => '类型名称',
+    'Gender'                => '适用性别',
+    'Type image'            => '类型示意图',
+    'Description'           => '类型描述',
+    'Sort'                  => '排序',
+    'Status'                => '状态',
+    'Createtime'            => '创建时间',
+    'Updatetime'            => '更新时间',
+    'Operate'               => '操作',
+    
+    // 分类选项
+    'Shoulder'              => '肩型',
+    'Chest(Male)'           => '胸型(男)',
+    'Bust(Female)'          => '胸型(女)',
+    'Waist'                 => '腰型',
+    'Hip'                   => '臀型',
+    'Leg'                   => '腿型',
+    
+    // 性别选项
+    'Universal'             => '通用',
+    'Male'                  => '男性',
+    'Female'                => '女性',
+    
+    // 状态选项
+    'Normal'                => '启用',
+    'Hidden'                => '禁用',
+    
+    // 操作按钮
+    'Preview'               => '预览',
+    'Import initial data'   => '导入初始数据',
+    'Sort management'       => '排序管理',
+    
+    // 提示信息
+    'Please select'         => '请选择',
+    'Sort saved successfully' => '排序保存成功',
+    
+    // 表单验证
+    'Type category can not be empty' => '类型分类不能为空',
+    'Type name can not be empty'     => '类型名称不能为空',
+    'The type configuration already exists' => '该体型配置已存在',
+    'The type has been selected by users and cannot be deleted' => '该体型已被用户选择,无法删除',
+    
+    // 导入相关
+    'Import success'        => '导入成功',
+    'Force import'          => '强制导入',
+    'Force import will clear existing data' => '强制导入会清空现有数据',
+    'The system already has type configuration data' => '系统中已存在体型配置数据',
+    'If you need to re-import, please check force import' => '如需重新导入请勾选强制导入',
+];

+ 47 - 0
application/admin/validate/BodyTypeConfig.php

@@ -0,0 +1,47 @@
+<?php
+
+namespace app\admin\validate;
+
+use think\Validate;
+
+class BodyTypeConfig extends Validate
+{
+    /**
+     * 验证规则
+     */
+    protected $rule = [
+        'type_category' => 'require|in:shoulder,chest,bust,waist,hip,leg',
+        'type_name'     => 'require|length:1,50',
+        'gender'        => 'require|in:0,1,2',
+        'type_image'    => 'url',
+        'description'   => 'length:0,255',
+        'sort'          => 'integer|egt:0',
+        'status'        => 'require|in:0,1',
+    ];
+
+    /**
+     * 提示消息
+     */
+    protected $message = [
+        'type_category.require' => '类型分类不能为空',
+        'type_category.in'      => '类型分类必须是有效值',
+        'type_name.require'     => '类型名称不能为空',
+        'type_name.length'      => '类型名称长度必须在1-50个字符之间',
+        'gender.require'        => '适用性别不能为空',
+        'gender.in'             => '适用性别必须是有效值',
+        'type_image.url'        => '类型示意图必须是有效的URL',
+        'description.length'    => '类型描述长度不能超过255个字符',
+        'sort.integer'          => '排序必须是整数',
+        'sort.egt'              => '排序必须大于等于0',
+        'status.require'        => '状态不能为空',
+        'status.in'             => '状态必须是有效值',
+    ];
+
+    /**
+     * 验证场景
+     */
+    protected $scene = [
+        'add'  => ['type_category', 'type_name', 'gender', 'type_image', 'description', 'sort', 'status'],
+        'edit' => ['type_category', 'type_name', 'gender', 'type_image', 'description', 'sort', 'status'],
+    ];
+}

+ 71 - 0
application/admin/view/body_type_config/add.html

@@ -0,0 +1,71 @@
+<form id="add-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Type category')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <select id="c-type_category" class="form-control selectpicker" name="row[type_category]" data-rule="required">
+                <option value="">{:__('Please select')}</option>
+                {foreach $categories as $key => $name}
+                <option value="{$key}">{$name}</option>
+                {/foreach}
+            </select>
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Type name')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-type_name" class="form-control" name="row[type_name]" type="text" data-rule="required" placeholder="请输入类型名称">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Gender')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <select id="c-gender" class="form-control selectpicker" name="row[gender]">
+                <option value="0">通用</option>
+                <option value="1">男性</option>
+                <option value="2">女性</option>
+            </select>
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Type image')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <div class="input-group">
+                <input id="c-type_image" class="form-control" size="50" name="row[type_image]" type="text" placeholder="请选择类型示意图">
+                <div class="input-group-addon no-border no-padding">
+                    <span><button type="button" id="faupload-type_image" class="btn btn-danger faupload" data-input-id="c-type_image" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp" data-multiple="false" data-preview-id="p-type_image"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
+                    <span><button type="button" id="fachoose-type_image" class="btn btn-primary fachoose" data-input-id="c-type_image" data-mimetype="image/*" data-multiple="false"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
+                </div>
+                <span class="msg-box n-right" for="c-type_image"></span>
+            </div>
+            <ul class="row list-inline faupload-preview" id="p-type_image"></ul>
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Description')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <textarea id="c-description" class="form-control" rows="3" name="row[description]" cols="50" placeholder="请输入类型描述"></textarea>
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Sort')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-sort" class="form-control" name="row[sort]" type="number" value="0" placeholder="数字越小排序越靠前">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <div class="radio">
+                <label for="row[status]-1"><input id="row[status]-1" name="row[status]" type="radio" value="1" checked> 启用</label> 
+                <label for="row[status]-0"><input id="row[status]-0" name="row[status]" type="radio" value="0"> 禁用</label> 
+            </div>
+        </div>
+    </div>
+    <div class="form-group layer-footer">
+        <label class="control-label col-xs-12 col-sm-2"></label>
+        <div class="col-xs-12 col-sm-8">
+            <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button>
+            <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
+        </div>
+    </div>
+</form>

+ 80 - 0
application/admin/view/body_type_config/edit.html

@@ -0,0 +1,80 @@
+<form id="edit-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Type category')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <select id="c-type_category" class="form-control selectpicker" name="row[type_category]" data-rule="required">
+                <option value="">{:__('Please select')}</option>
+                {foreach $categories as $key => $name}
+                <option value="{$key}" {if $row.type_category==$key}selected{/if}>{$name}</option>
+                {/foreach}
+            </select>
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Type name')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-type_name" class="form-control" name="row[type_name]" type="text" value="{$row.type_name|htmlentities}" data-rule="required" placeholder="请输入类型名称">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Gender')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <select id="c-gender" class="form-control selectpicker" name="row[gender]">
+                <option value="0" {if $row.gender==0}selected{/if}>通用</option>
+                <option value="1" {if $row.gender==1}selected{/if}>男性</option>
+                <option value="2" {if $row.gender==2}selected{/if}>女性</option>
+            </select>
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Type image')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <div class="input-group">
+                <input id="c-type_image" class="form-control" size="50" name="row[type_image]" type="text" value="{$row.type_image|htmlentities}" placeholder="请选择类型示意图">
+                <div class="input-group-addon no-border no-padding">
+                    <span><button type="button" id="faupload-type_image" class="btn btn-danger faupload" data-input-id="c-type_image" data-mimetype="image/gif,image/jpeg,image/png,image/jpg,image/bmp" data-multiple="false" data-preview-id="p-type_image"><i class="fa fa-upload"></i> {:__('Upload')}</button></span>
+                    <span><button type="button" id="fachoose-type_image" class="btn btn-primary fachoose" data-input-id="c-type_image" data-mimetype="image/*" data-multiple="false"><i class="fa fa-list"></i> {:__('Choose')}</button></span>
+                </div>
+                <span class="msg-box n-right" for="c-type_image"></span>
+            </div>
+            <ul class="row list-inline faupload-preview" id="p-type_image">
+                {if $row.type_image}
+                <li data-url="{$row.type_image}">
+                    <div class="faupload-preview-item">
+                        <img src="{$row.type_image}" class="img-responsive">
+                        <a href="javascript:;" class="btn btn-xs btn-white btn-remove"><i class="fa fa-remove"></i></a>
+                    </div>
+                </li>
+                {/if}
+            </ul>
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Description')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <textarea id="c-description" class="form-control" rows="3" name="row[description]" cols="50" placeholder="请输入类型描述">{$row.description|htmlentities}</textarea>
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Sort')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <input id="c-sort" class="form-control" name="row[sort]" type="number" value="{$row.sort}" placeholder="数字越小排序越靠前">
+        </div>
+    </div>
+    <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">{:__('Status')}:</label>
+        <div class="col-xs-12 col-sm-8">
+            <div class="radio">
+                <label for="row[status]-1"><input id="row[status]-1" name="row[status]" type="radio" value="1" {if $row.status==1}checked{/if}> 启用</label> 
+                <label for="row[status]-0"><input id="row[status]-0" name="row[status]" type="radio" value="0" {if $row.status==0}checked{/if}> 禁用</label> 
+            </div>
+        </div>
+    </div>
+    <div class="form-group layer-footer">
+        <label class="control-label col-xs-12 col-sm-2"></label>
+        <div class="col-xs-12 col-sm-8">
+            <button type="submit" class="btn btn-success btn-embossed disabled">{:__('OK')}</button>
+            <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
+        </div>
+    </div>
+</form>

+ 110 - 0
application/admin/view/body_type_config/import.html

@@ -0,0 +1,110 @@
+<form id="import-form" class="form-horizontal" role="form" data-toggle="validator" method="POST" action="">
+    <div class="panel panel-default panel-intro">
+        <div class="panel-heading">
+            <div class="panel-lead"><em>导入初始数据</em></div>
+        </div>
+        <div class="panel-body">
+            <div class="row">
+                <div class="col-xs-12">
+                    <div class="alert alert-info">
+                        <i class="fa fa-info-circle"></i> 当前系统中共有 <strong>{$count}</strong> 条体型配置数据
+                    </div>
+                </div>
+            </div>
+            
+            {if $count > 0}
+            <div class="row">
+                <div class="col-xs-12">
+                    <div class="alert alert-warning">
+                        <i class="fa fa-warning"></i> 系统中已存在体型配置数据,如需重新导入请勾选下方的"强制导入"选项
+                    </div>
+                </div>
+            </div>
+            
+            <div class="form-group">
+                <label class="control-label col-xs-12 col-sm-2">导入选项:</label>
+                <div class="col-xs-12 col-sm-8">
+                    <div class="checkbox">
+                        <label for="c-force">
+                            <input id="c-force" name="force" type="checkbox" value="1"> 
+                            强制导入(会清空现有数据)
+                        </label>
+                    </div>
+                </div>
+            </div>
+            {/if}
+            
+            <div class="row">
+                <div class="col-xs-12">
+                    <div class="panel panel-default">
+                        <div class="panel-heading">
+                            <h4 class="panel-title">将导入以下体型配置数据:</h4>
+                        </div>
+                        <div class="panel-body">
+                            <div class="row">
+                                <div class="col-md-4">
+                                    <h5><span class="label label-primary">肩型</span></h5>
+                                    <ul class="list-unstyled">
+                                        <li>• 平肩(通用)</li>
+                                        <li>• 溜肩(通用)</li>
+                                        <li>• 削肩(通用)</li>
+                                    </ul>
+                                </div>
+                                <div class="col-md-4">
+                                    <h5><span class="label label-info">胸型(男)</span></h5>
+                                    <ul class="list-unstyled">
+                                        <li>• 平胸(男性)</li>
+                                        <li>• 肌肉(男性)</li>
+                                        <li>• 圆胸(男性)</li>
+                                    </ul>
+                                    
+                                    <h5><span class="label label-danger">胸型(女)</span></h5>
+                                    <ul class="list-unstyled">
+                                        <li>• 小巧(女性)</li>
+                                        <li>• 正常(女性)</li>
+                                        <li>• 丰满(女性)</li>
+                                        <li>• 胖(女性)</li>
+                                    </ul>
+                                </div>
+                                <div class="col-md-4">
+                                    <h5><span class="label label-success">腰型</span></h5>
+                                    <ul class="list-unstyled">
+                                        <li>• 细腰(通用)</li>
+                                        <li>• 正常(通用)</li>
+                                        <li>• 圆腰(通用)</li>
+                                    </ul>
+                                    
+                                    <h5><span class="label label-warning">臀型</span></h5>
+                                    <ul class="list-unstyled">
+                                        <li>• 平臀(通用)</li>
+                                        <li>• 正常(通用)</li>
+                                        <li>• 翘臀(通用)</li>
+                                    </ul>
+                                    
+                                    <h5><span class="label label-default">腿型</span></h5>
+                                    <ul class="list-unstyled">
+                                        <li>• 直腿(通用)</li>
+                                        <li>• O型腿(通用)</li>
+                                        <li>• X型腿(通用)</li>
+                                    </ul>
+                                </div>
+                            </div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            
+            <div class="form-group layer-footer">
+                <label class="control-label col-xs-12 col-sm-2"></label>
+                <div class="col-xs-12 col-sm-8">
+                    <button type="submit" class="btn btn-success btn-embossed">
+                        <i class="fa fa-download"></i> 开始导入
+                    </button>
+                    <button type="button" class="btn btn-default btn-embossed" onclick="parent.Fast.api.close();">
+                        取消
+                    </button>
+                </div>
+            </div>
+        </div>
+    </div>
+</form>

+ 37 - 0
application/admin/view/body_type_config/index.html

@@ -0,0 +1,37 @@
+<div class="panel panel-default panel-intro">
+    <div class="panel-heading">
+        <ul class="nav nav-tabs">
+            <li class="active"><a href="#t-all" data-toggle="tab">{:__('All')}</a></li>
+        </ul>
+    </div>
+    <div class="panel-body">
+        <div id="myTabContent" class="tab-content">
+            <div class="tab-pane fade active in" id="t-all">
+                <div class="widget-body no-padding">
+                    <div id="toolbar" class="toolbar">
+                        <a href="javascript:;" class="btn btn-primary btn-refresh" title="{:__('Refresh')}" ><i class="fa fa-refresh"></i> </a>
+                         <a href="javascript:;" class="btn btn-success btn-add" title="{:__('Add')}" ><i class="fa fa-plus"></i> {:__('Add')}</a>
+                        <!--<a href="javascript:;" class="btn btn-success btn-edit btn-disabled disabled" title="{:__('Edit')}" ><i class="fa fa-pencil"></i> {:__('Edit')}</a>
+                        <a href="javascript:;" class="btn btn-danger btn-del btn-disabled disabled" title="{:__('Delete')}" ><i class="fa fa-trash"></i> {:__('Delete')}</a>
+                        <a href="javascript:;" class="btn btn-info btn-import" title="导入初始数据" ><i class="fa fa-download"></i> 导入初始数据</a>
+                        <a href="javascript:;" class="btn btn-warning btn-sort" title="排序管理" ><i class="fa fa-sort"></i> 排序管理</a>
+                        
+                        <div class="dropdown btn-group">
+                            <a class="btn btn-primary btn-more dropdown-toggle btn-disabled disabled" data-toggle="dropdown"><i class="fa fa-cog"></i> {:__('More')}</a>
+                            <ul class="dropdown-menu text-left" role="menu">
+                                <li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=normal"><i class="fa fa-eye"></i> {:__('Set to normal')}</a></li>
+                                <li><a class="btn btn-link btn-multi btn-disabled disabled" href="javascript:;" data-params="status=hidden"><i class="fa fa-eye-slash"></i> {:__('Set to hidden')}</a></li>
+                            </ul>
+                        </div> -->
+                    </div>
+                    <table id="table" class="table table-striped table-bordered table-hover table-nowrap"
+                           data-operate-edit="{:$auth->check('body_type_config/edit')}"
+                           data-operate-del="{:$auth->check('body_type_config/del')}"
+                           width="100%">
+                    </table>
+                </div>
+            </div>
+
+        </div>
+    </div>
+</div>

+ 89 - 0
application/admin/view/body_type_config/preview.html

@@ -0,0 +1,89 @@
+<div class="panel panel-default panel-intro">
+    <div class="panel-heading">
+        <div class="panel-lead"><em>体型配置预览</em></div>
+    </div>
+    <div class="panel-body">
+        <div class="row">
+            <div class="col-md-6">
+                <table class="table table-bordered">
+                    <tr>
+                        <th width="120">分类</th>
+                        <td>
+                            <span class="label label-primary">{$row.type_category}</span>
+                            {if $row.type_category == 'shoulder'}肩型
+                            {elseif $row.type_category == 'chest'}胸型(男)
+                            {elseif $row.type_category == 'bust'}胸型(女)
+                            {elseif $row.type_category == 'waist'}腰型
+                            {elseif $row.type_category == 'hip'}臀型
+                            {elseif $row.type_category == 'leg'}腿型
+                            {/if}
+                        </td>
+                    </tr>
+                    <tr>
+                        <th>类型名称</th>
+                        <td><strong>{$row.type_name}</strong></td>
+                    </tr>
+                    <tr>
+                        <th>适用性别</th>
+                        <td>
+                            {if $row.gender == 0}
+                            <span class="label label-default">通用</span>
+                            {elseif $row.gender == 1}
+                            <span class="label label-info">男性</span>
+                            {else}
+                            <span class="label label-danger">女性</span>
+                            {/if}
+                        </td>
+                    </tr>
+                    <tr>
+                        <th>排序</th>
+                        <td>{$row.sort}</td>
+                    </tr>
+                    <tr>
+                        <th>状态</th>
+                        <td>
+                            {if $row.status == 1}
+                            <span class="label label-success">启用</span>
+                            {else}
+                            <span class="label label-warning">禁用</span>
+                            {/if}
+                        </td>
+                    </tr>
+                    <tr>
+                        <th>创建时间</th>
+                        <td>{$row.createtime|date="Y-m-d H:i:s"}</td>
+                    </tr>
+                    <tr>
+                        <th>更新时间</th>
+                        <td>{$row.updatetime|date="Y-m-d H:i:s"}</td>
+                    </tr>
+                </table>
+            </div>
+            <div class="col-md-6">
+                <div class="form-group">
+                    <label>类型描述:</label>
+                    <div class="well well-sm">
+                        {$row.description|default="暂无描述"}
+                    </div>
+                </div>
+                
+                {if $row.type_image}
+                <div class="form-group">
+                    <label>类型示意图:</label>
+                    <div class="text-center">
+                        <img src="{$row.type_image}" class="img-responsive img-thumbnail" style="max-width: 300px; max-height: 300px;" alt="类型示意图">
+                    </div>
+                </div>
+                {else}
+                <div class="form-group">
+                    <label>类型示意图:</label>
+                    <div class="well well-sm text-center text-muted">
+                        <i class="fa fa-image fa-3x"></i>
+                        <p>暂无示意图</p>
+                    </div>
+                </div>
+                {/if}
+            </div>
+        </div>
+    </div>
+</div>

+ 63 - 0
application/admin/view/body_type_config/sort.html

@@ -0,0 +1,63 @@
+<div class="panel panel-default panel-intro">
+    <div class="panel-heading">
+        <div class="panel-lead"><em>排序管理</em></div>
+        <ul class="nav nav-tabs" data-field="type_category">
+            <li class="active"><a href="#t-all" data-toggle="tab" data-value="">全部</a></li>
+            <li><a href="#t-shoulder" data-toggle="tab" data-value="shoulder">肩型</a></li>
+            <li><a href="#t-chest" data-toggle="tab" data-value="chest">胸型(男)</a></li>
+            <li><a href="#t-bust" data-toggle="tab" data-value="bust">胸型(女)</a></li>
+            <li><a href="#t-waist" data-toggle="tab" data-value="waist">腰型</a></li>
+            <li><a href="#t-hip" data-toggle="tab" data-value="hip">臀型</a></li>
+            <li><a href="#t-leg" data-toggle="tab" data-value="leg">腿型</a></li>
+        </ul>
+    </div>
+    <div class="panel-body">
+        <div class="row">
+            <div class="col-xs-12">
+                <div class="alert alert-info-light">
+                    <i class="fa fa-info-circle"></i> 提示:拖拽下方的项目可以进行排序,排序会实时保存
+                </div>
+            </div>
+        </div>
+        <div class="row">
+            <div class="col-xs-12">
+                <ul id="sortable" class="list-group sortable">
+                    {foreach $list as $item}
+                    <li class="list-group-item" data-id="{$item.id}">
+                        <div class="row">
+                            <div class="col-xs-1">
+                                <i class="fa fa-arrows-v handle"></i>
+                            </div>
+                            <div class="col-xs-2">
+                                <span class="label label-primary">{$item.type_category}</span>
+                            </div>
+                            <div class="col-xs-3">
+                                <strong>{$item.type_name}</strong>
+                            </div>
+                            <div class="col-xs-2">
+                                {if $item.gender == 0}
+                                <span class="label label-default">通用</span>
+                                {elseif $item.gender == 1}
+                                <span class="label label-info">男性</span>
+                                {else}
+                                <span class="label label-danger">女性</span>
+                                {/if}
+                            </div>
+                            <div class="col-xs-3">
+                                {$item.description}
+                            </div>
+                            <div class="col-xs-1">
+                                {if $item.status == 1}
+                                <span class="label label-success">启用</span>
+                                {else}
+                                <span class="label label-warning">禁用</span>
+                                {/if}
+                            </div>
+                        </div>
+                    </li>
+                    {/foreach}
+                </ul>
+            </div>
+        </div>
+    </div>
+</div>

+ 14 - 0
application/admin/view/version/add.html

@@ -13,6 +13,20 @@
         </div>
     </div>
     <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">平台:</label>
+        <div class="col-xs-12 col-sm-8">
+            <!-- 渠道选择 -->
+            <div class="channel-list">
+                {foreach name="platformList" item="vo" key="key"}
+                <label class="radio-inline">
+                    <input type="radio" name="row[platform]" value="{$key}" data-rule="checked" data-rule-message="请至少选择一个活动渠道"> 
+                    {$vo}
+                </label>
+                {/foreach}
+            </div>
+        </div>
+    </div>
+    <div class="form-group">
         <label for="c-iteration_version" class="control-label col-xs-12 col-sm-2">{:__('Iterationversion')}:</label>
         <div class="col-xs-12 col-sm-8">
             <input id="c-iteration_version" class="form-control" name="row[iteration_version]" type="text" value="">

+ 14 - 0
application/admin/view/version/edit.html

@@ -7,6 +7,20 @@
         </div>
     </div>
     <div class="form-group">
+        <label class="control-label col-xs-12 col-sm-2">平台:</label>
+        <div class="col-xs-12 col-sm-8">
+            <!-- 渠道选择 -->
+            <div class="channel-list">
+                {foreach name="platformList" item="vo" key="key"}
+                <label class="radio-inline">
+                    <input type="radio" name="row[platform]" value="{$key}" data-rule="checked" data-rule-message="请至少选择一个活动渠道" {if condition="is_array($row.platform) && in_array($key, $row.platform)"}checked{/if}> 
+                    {$vo}
+                </label>
+                {/foreach}
+            </div>
+        </div>
+    </div>
+    <div class="form-group">
         <label for="c-iteration_version" class="control-label col-xs-12 col-sm-2">{:__('Iterationversion')}:</label>
         <div class="col-xs-12 col-sm-8">
             <input id="c-iteration_version" class="form-control" name="row[iteration_version]" type="text" value="{$row.iteration_version}">

+ 2 - 0
application/api/controller/Version.php

@@ -25,5 +25,7 @@ class Version extends Base
         $this->success('返回成功', $this->request->param());
     }
 
+    
+
    
 }

+ 1 - 0
body_type_config_menu.sql

@@ -0,0 +1 @@
+ 

+ 66 - 0
install_body_type_config.sql

@@ -0,0 +1,66 @@
+-- 身体类型配置模块安装脚本
+-- 包含数据表创建和菜单项添加
+
+-- 1. 创建身体类型配置表
+CREATE TABLE IF NOT EXISTS `fa_body_type_config` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `type_category` varchar(50) NOT NULL DEFAULT '' COMMENT '类型分类(shoulder/chest/waist/hip/leg/bust等)',
+  `type_name` varchar(50) NOT NULL DEFAULT '' COMMENT '类型名称',
+  `gender` tinyint(1) NOT NULL DEFAULT '0' COMMENT '适用性别 0=通用 1=男 2=女',
+  `type_image` varchar(255) NOT NULL DEFAULT '' COMMENT '类型示意图',
+  `description` varchar(255) NOT NULL DEFAULT '' COMMENT '类型描述',
+  `sort` int(5) NOT NULL DEFAULT '0' COMMENT '排序',
+  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态 1=启用 0=禁用',
+  `createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
+  `updatetime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
+  PRIMARY KEY (`id`),
+  KEY `type_category` (`type_category`),
+  KEY `gender` (`gender`),
+  KEY `sort` (`sort`)
+) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4 COMMENT='身体类型配置表';
+
+-- 2. 添加菜单项到权限规则表
+-- 首先查找合适的父级菜单(这里使用ID=2的常规管理,如果不存在则创建为顶级菜单)
+SET @parent_id = (SELECT id FROM fa_auth_rule WHERE name = 'general' AND ismenu = 1 LIMIT 1);
+SET @parent_id = IFNULL(@parent_id, 0);
+
+-- 插入主菜单项
+INSERT INTO `fa_auth_rule` (`type`, `pid`, `name`, `title`, `icon`, `url`, `condition`, `remark`, `ismenu`, `menutype`, `extend`, `py`, `pinyin`, `createtime`, `updatetime`, `weigh`, `status`) 
+VALUES ('file', @parent_id, 'body_type_config', '身体类型配置', 'fa fa-user-md', '', '', '身体类型配置管理', 1, NULL, '', 'stlxpz', 'shentileixingpeizhi', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 90, 'normal')
+ON DUPLICATE KEY UPDATE 
+    `title` = '身体类型配置',
+    `icon` = 'fa fa-user-md',
+    `remark` = '身体类型配置管理',
+    `updatetime` = UNIX_TIMESTAMP();
+
+-- 获取主菜单ID
+SET @main_menu_id = (SELECT id FROM fa_auth_rule WHERE name = 'body_type_config' LIMIT 1);
+
+-- 插入子菜单项
+INSERT INTO `fa_auth_rule` (`type`, `pid`, `name`, `title`, `icon`, `url`, `condition`, `remark`, `ismenu`, `menutype`, `extend`, `py`, `pinyin`, `createtime`, `updatetime`, `weigh`, `status`) VALUES
+('file', @main_menu_id, 'body_type_config/index', '查看', 'fa fa-list', '', '', '', 0, NULL, '', 'ck', 'chakan', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 0, 'normal'),
+('file', @main_menu_id, 'body_type_config/add', '添加', 'fa fa-plus', '', '', '', 0, NULL, '', 'tj', 'tianjia', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 0, 'normal'),
+('file', @main_menu_id, 'body_type_config/edit', '编辑', 'fa fa-pencil', '', '', '', 0, NULL, '', 'bj', 'bianji', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 0, 'normal'),
+('file', @main_menu_id, 'body_type_config/del', '删除', 'fa fa-trash', '', '', '', 0, NULL, '', 'sc', 'shanchu', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 0, 'normal'),
+('file', @main_menu_id, 'body_type_config/multi', '批量更新', 'fa fa-list', '', '', '', 0, NULL, '', 'plgx', 'pilianggenxin', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 0, 'normal'),
+('file', @main_menu_id, 'body_type_config/import', '导入初始数据', 'fa fa-download', '', '', '', 0, NULL, '', 'drcsj', 'daoruchushishuju', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 0, 'normal'),
+('file', @main_menu_id, 'body_type_config/sort', '排序管理', 'fa fa-sort', '', '', '', 0, NULL, '', 'pxgl', 'paixuguanli', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 0, 'normal'),
+('file', @main_menu_id, 'body_type_config/preview', '预览', 'fa fa-eye', '', '', '', 0, NULL, '', 'yl', 'yulan', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), 0, 'normal')
+ON DUPLICATE KEY UPDATE 
+    `title` = VALUES(`title`),
+    `icon` = VALUES(`icon`),
+    `updatetime` = UNIX_TIMESTAMP();
+
+-- 3. 为超级管理员组添加权限(组ID通常为1)
+INSERT IGNORE INTO `fa_auth_group_access` (`uid`, `group_id`) 
+SELECT 1, 1 WHERE NOT EXISTS (SELECT 1 FROM `fa_auth_group_access` WHERE `uid` = 1 AND `group_id` = 1);
+
+-- 4. 更新超级管理员组的权限规则(添加新的菜单权限)
+UPDATE `fa_auth_group` SET 
+    `rules` = CONCAT(IFNULL(`rules`, ''), ',', (SELECT GROUP_CONCAT(id) FROM fa_auth_rule WHERE name LIKE 'body_type_config%'))
+WHERE `id` = 1 AND `rules` NOT LIKE '%body_type_config%';
+
+-- 完成提示
+SELECT '身体类型配置模块安装完成!' AS message;
+SELECT CONCAT('主菜单ID: ', @main_menu_id) AS menu_info;
+SELECT '请清除缓存并刷新后台页面查看新菜单' AS notice;

+ 195 - 0
public/assets/js/backend/body_type_config.js

@@ -0,0 +1,195 @@
+define(['jquery', 'bootstrap', 'backend', 'table', 'form'], function ($, undefined, Backend, Table, Form) {
+
+    var Controller = {
+        index: function () {
+            // 初始化表格参数配置
+            Table.api.init({
+                extend: {
+                    index_url: 'body_type_config/index' + location.search,
+                    add_url: 'body_type_config/add',
+                    edit_url: 'body_type_config/edit',
+                    del_url: 'body_type_config/del',
+                    multi_url: 'body_type_config/multi',
+                    import_url: 'body_type_config/import',
+                    sort_url: 'body_type_config/sort',
+                    table: 'body_type_config',
+                }
+            });
+
+            var table = $("#table");
+
+            // 初始化表格
+            table.bootstrapTable({
+                url: $.fn.bootstrapTable.defaults.extend.index_url,
+                pk: 'id',
+                sortName: 'type_category,sort,id',
+                fixedColumns: true,
+                fixedRightNumber: 1,
+                columns: [
+                    [
+                        {checkbox: true},
+                        {field: 'id', title: __('Id'), sortable: true},
+                        {
+                            field: 'type_category', 
+                            title: __('Type category'), 
+                            searchList: {
+                                "shoulder": __('Shoulder'),
+                                "chest": __('Chest(Male)'),
+                                "bust": __('Bust(Female)'),
+                                "waist": __('Waist'),
+                                "hip": __('Hip'),
+                                "leg": __('Leg')
+                            },
+                            formatter: function (value, row, index) {
+                                var categoryMap = {
+                                    'shoulder': '肩型',
+                                    'chest': '胸型(男)',
+                                    'bust': '胸型(女)',
+                                    'waist': '腰型',
+                                    'hip': '臀型',
+                                    'leg': '腿型'
+                                };
+                                var colorMap = {
+                                    'shoulder': 'primary',
+                                    'chest': 'info',
+                                    'bust': 'danger',
+                                    'waist': 'success',
+                                    'hip': 'warning',
+                                    'leg': 'default'
+                                };
+                                return '<span class="label label-' + (colorMap[value] || 'default') + '">' + (categoryMap[value] || value) + '</span>';
+                            }
+                        },
+                        {field: 'type_name', title: __('Type name'), operate: 'LIKE'},
+                        {
+                            field: 'gender', 
+                            title: __('Gender'), 
+                            searchList: {"0": __('Universal'), "1": __('Male'), "2": __('Female')}, 
+                            formatter: function (value, row, index) {
+                                var genderMap = {0: '通用', 1: '男性', 2: '女性'};
+                                var colorMap = {0: 'default', 1: 'info', 2: 'danger'};
+                                return '<span class="label label-' + colorMap[value] + '">' + genderMap[value] + '</span>';
+                            }
+                        },
+                        {
+                            field: 'type_image', 
+                            title: __('Type image'), 
+                            operate: false, 
+                            events: Table.api.events.image, 
+                            formatter: Table.api.formatter.image,
+                            addClass: 'text-center'
+                        },
+                        {field: 'description', title: __('Description'), operate: 'LIKE', addClass: 'text-left'},
+                        {field: 'sort', title: __('Sort'), operate: false},
+                        {
+                            field: 'status', 
+                            title: __('Status'), 
+                            searchList: {"1": __('Normal'), "0": __('Hidden')}, 
+                            formatter: Table.api.formatter.status
+                        },
+                        {field: 'createtime', title: __('Createtime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
+                        {field: 'updatetime', title: __('Updatetime'), operate:'RANGE', addclass:'datetimerange', autocomplete:false, formatter: Table.api.formatter.datetime},
+                        {
+                            field: 'operate', 
+                            title: __('Operate'), 
+                            table: table, 
+                            events: Table.api.events.operate, 
+                            buttons: [
+                                {
+                                    name: 'preview',
+                                    title: __('Preview'),
+                                    classname: 'btn btn-xs btn-info btn-dialog',
+                                    icon: 'fa fa-eye',
+                                    url: 'body_type_config/preview'
+                                }
+                            ],
+                            formatter: Table.api.formatter.operate
+                        }
+                    ]
+                ]
+            });
+
+            // 为表格绑定事件
+            Table.api.bindevent(table);
+
+            // 导入初始数据按钮
+            $(document).on('click', '.btn-import', function () {
+                Fast.api.open('body_type_config/import', __('Import initial data'), {
+                    callback: function (data) {
+                        Layer.alert("导入成功!", function (index) {
+                            $(".btn-refresh").trigger("click");
+                            Layer.close(index);
+                        });
+                    }
+                });
+            });
+
+            // 排序管理按钮
+            $(document).on('click', '.btn-sort', function () {
+                Fast.api.open('body_type_config/sort', __('Sort management'), {
+                    area: ['90%', '90%'],
+                    callback: function (data) {
+                        Layer.alert("排序保存成功!", function (index) {
+                            $(".btn-refresh").trigger("click");
+                            Layer.close(index);
+                        });
+                    }
+                });
+            });
+        },
+        add: function () {
+            Controller.api.bindevent();
+        },
+        edit: function () {
+            Controller.api.bindevent();
+        },
+        sort: function () {
+            // 初始化排序
+            require(['sortable'], function (Sortable) {
+                var sortable = new Sortable(document.getElementById('sortable'), {
+                    handle: '.handle',
+                    animation: 150,
+                    onEnd: function (evt) {
+                        var ids = [];
+                        $('#sortable li').each(function () {
+                            ids.push($(this).data('id'));
+                        });
+                        
+                        // 发送排序请求
+                        Fast.api.ajax({
+                            url: 'body_type_config/sort',
+                            data: {ids: ids}
+                        }, function (data, ret) {
+                            Toastr.success(__('Sort saved successfully'));
+                        });
+                    }
+                });
+            });
+
+            // 分类切换
+            $(document).on('click', '.nav-tabs a', function (e) {
+                e.preventDefault();
+                var type_category = $(this).data('value');
+                var url = 'body_type_config/sort';
+                if (type_category) {
+                    url += '?type_category=' + type_category;
+                }
+                Fast.api.open(url, __('Sort management'), {
+                    area: ['90%', '90%']
+                });
+            });
+        },
+        import: function () {
+            Controller.api.bindevent();
+        },
+        preview: function () {
+            // 预览页面不需要特殊处理
+        },
+        api: {
+            bindevent: function () {
+                Form.api.bindevent($("form[role=form]"));
+            }
+        }
+    };
+    return Controller;
+});

+ 219 - 0
身体类型配置模块使用说明.md

@@ -0,0 +1,219 @@
+# 身体类型配置模块使用说明
+
+## 模块概述
+
+身体类型配置模块用于管理系统中的身体类型分类和具体类型,支持按性别分类管理,为用户选择体型提供基础数据。
+
+## 文件结构
+
+### 后端文件
+```
+application/admin/
+├── controller/BodyTypeConfig.php          # 后台控制器
+├── view/body_type_config/                 # 视图文件目录
+│   ├── index.html                         # 列表页面
+│   ├── add.html                          # 添加页面
+│   ├── edit.html                         # 编辑页面
+│   ├── sort.html                         # 排序页面
+│   ├── import.html                       # 导入页面
+│   └── preview.html                      # 预览页面
+└── lang/zh-cn/body_type_config.php       # 语言包
+
+application/common/
+└── model/BodyTypeConfig.php               # 数据模型
+
+public/assets/js/backend/
+└── body_type_config.js                   # 前端JavaScript
+```
+
+### 安装文件
+```
+install_body_type_config.sql               # 完整安装脚本
+body_type_config_menu.sql                  # 仅菜单安装脚本
+```
+
+## 安装步骤
+
+### 1. 数据库安装
+执行安装脚本创建数据表和菜单项:
+```sql
+source install_body_type_config.sql;
+```
+
+或者手动执行:
+```sql
+-- 创建数据表
+CREATE TABLE `fa_body_type_config` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
+  `type_category` varchar(50) NOT NULL DEFAULT '' COMMENT '类型分类',
+  `type_name` varchar(50) NOT NULL DEFAULT '' COMMENT '类型名称',
+  `gender` tinyint(1) NOT NULL DEFAULT '0' COMMENT '适用性别 0=通用 1=男 2=女',
+  `type_image` varchar(255) NOT NULL DEFAULT '' COMMENT '类型示意图',
+  `description` varchar(255) NOT NULL DEFAULT '' COMMENT '类型描述',
+  `sort` int(5) NOT NULL DEFAULT '0' COMMENT '排序',
+  `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态',
+  `createtime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '创建时间',
+  `updatetime` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '更新时间',
+  PRIMARY KEY (`id`),
+  KEY `type_category` (`type_category`),
+  KEY `gender` (`gender`),
+  KEY `sort` (`sort`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='身体类型配置表';
+```
+
+### 2. 清除缓存
+安装完成后需要清除系统缓存:
+```bash
+# 清除权限缓存
+rm -rf runtime/cache/
+# 或在后台系统管理->系统缓存中清除
+```
+
+### 3. 权限分配
+如果需要为其他管理员组分配权限:
+1. 进入后台 -> 权限管理 -> 角色组
+2. 编辑对应角色组
+3. 勾选"身体类型配置"相关权限
+
+## 功能说明
+
+### 1. 类型分类
+系统预定义了以下分类:
+- `shoulder` - 肩型
+- `chest` - 胸型(男)
+- `bust` - 胸型(女)
+- `waist` - 腰型
+- `hip` - 臀型
+- `leg` - 腿型
+
+### 2. 性别适用
+- `0` - 通用(男女都适用)
+- `1` - 仅限男性
+- `2` - 仅限女性
+
+### 3. 主要功能
+- **列表管理**:查看所有体型配置,支持按分类、性别筛选
+- **添加/编辑**:新增或修改体型配置信息
+- **排序管理**:拖拽排序,支持按分类分组排序
+- **导入初始数据**:一键导入系统预设的体型数据
+- **状态管理**:启用/禁用体型配置
+- **预览功能**:查看体型配置详情
+
+### 4. 初始数据
+系统提供了丰富的初始数据:
+
+#### 肩型(通用)
+- 平肩、溜肩、削肩
+
+#### 胸型(男性)
+- 平胸、肌肉、圆胸
+
+#### 胸型(女性)
+- 小巧、正常、丰满、胖
+
+#### 腰型(通用)
+- 细腰、正常、圆腰
+
+#### 臀型(通用)
+- 平臀、正常、翘臀
+
+#### 腿型(通用)
+- 直腿、O型腿、X型腿
+
+## API接口
+
+### 获取体型配置选项
+```
+GET /api/body_profile/getBodyTypeOptions?gender=0
+```
+
+参数:
+- `gender` - 性别筛选(0=全部,1=男性,2=女性)
+
+返回示例:
+```json
+{
+  "code": 1,
+  "msg": "获取成功",
+  "data": {
+    "shoulder": {
+      "name": "肩型",
+      "description": "肩部形态分类",
+      "icon": "fa fa-user",
+      "types": [
+        {"id": 1, "type_name": "平肩", "description": "肩部线条平直"},
+        {"id": 2, "type_name": "溜肩", "description": "肩部向下倾斜"}
+      ],
+      "measurement_fields": ["shoulder_width"]
+    }
+  }
+}
+```
+
+## 使用注意事项
+
+### 1. 删除限制
+- 已被用户选择的体型配置无法删除
+- 删除前系统会检查关联的用户选择记录
+
+### 2. 分类扩展
+如需添加新的分类,需要:
+1. 在控制器中更新 `$categories` 数组
+2. 在语言包中添加对应翻译
+3. 在前端JavaScript中更新分类映射
+
+### 3. 图片上传
+- 支持上传类型示意图
+- 建议图片尺寸:300x300像素
+- 支持格式:JPG, PNG, GIF
+
+### 4. 排序说明
+- 数字越小排序越靠前
+- 支持按分类分组排序
+- 拖拽排序会自动保存
+
+## 故障排除
+
+### 1. 菜单不显示
+- 检查权限是否正确分配
+- 清除系统缓存
+- 确认菜单项是否正确插入
+
+### 2. 接口返回空数据
+- 检查数据表是否创建成功
+- 确认是否导入了初始数据
+- 检查数据状态是否为启用
+
+### 3. 图片上传失败
+- 检查上传目录权限
+- 确认文件大小限制
+- 检查文件格式是否支持
+
+## 开发扩展
+
+### 1. 添加新字段
+如需为体型配置添加新字段:
+1. 修改数据表结构
+2. 更新模型文件
+3. 修改视图表单
+4. 更新验证规则
+
+### 2. 自定义分类
+添加新的体型分类:
+1. 在控制器中添加分类定义
+2. 更新前端分类映射
+3. 添加对应的语言翻译
+
+### 3. 接口扩展
+如需扩展API接口:
+1. 在 `BodyProfile` 控制器中添加新方法
+2. 更新路由配置
+3. 添加接口文档
+
+## 版本信息
+
+- 版本:1.0.0
+- 兼容:FastAdmin 1.x
+- 依赖:ThinkPHP 5.x
+- 作者:系统开发团队
+- 更新日期:2024年