tj
2025-03-20 a35f4b4d0c555493cc464bfd36d037230547f1aa
1.高级安全防护
已修改3个文件
已添加7个文件
1627 ■■■■■ 文件已修改
README.md 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/Editor.vue 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/CloudContent.vue 234 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/SecurityList.vue 219 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/SysDictList.vue 227 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/modules/CloudContentModal.vue 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/modules/SecurityModal.vue 173 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/modules/SysDictItemModal.vue 267 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/modules/SysDictModal.vue 146 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
README.md
@@ -1,4 +1,80 @@
## jspERP-web
node -v v16.20.2
jshERP-web Vue
#### 前端技术
- 基础框架:[ant-design-vue](https://github.com/vueComponent/ant-design-vue) - Ant Design Of Vue 实现
- JavaScript框架:Vue
- Jeecg-boot 的前段UI框架
- Webpack
- node
- yarn
- eslint
- @vue/cli 3.2.1
- [vue-cropper](https://github.com/xyxiao001/vue-cropper) - 头像裁剪组件
- [@antv/g2](https://antv.alipay.com/zh-cn/index.html) - Alipay AntV 数据可视化图表
- [Viser-vue](https://viserjs.github.io/docs.html#/viser/guide/installation)  - antv/g2 封装实现
项目运行
----
- 安装nodeJS
```
建议安装node-v20.17.0-x64版本 教程参考 https://blog.csdn.net/Coin_Collecter/article/details/136484312
```
- 安装yarn
```
npm install -g yarn
```
- 配镜像源(速度快)
```
yarn config set registry https://registry.npmmirror.com
```
- 安装依赖
```
yarn install
```
- 开发模式运行
```
yarn serve
```
- 编译发布项目
```
yarn build
```
其他说明
----
- 项目使用的 [vue-cli3](https://cli.vuejs.org/guide/), 请更新您的 cli
- 关闭 Eslint (不推荐) 移除 `package.json` 中 `eslintConfig` 整个节点代码
- 修改 Ant Design 配色,在文件 `vue.config.js` 中,其他 less 变量覆盖参考 [ant design](https://ant.design/docs/react/customize-theme-cn) 官方说明
```ecmascript 6
  css: {
    loaderOptions: {
      less: {
        modifyVars: {
          /* less 变量覆盖,用于自定义 ant design 主题 */
          'primary-color': '#F5222D',
          'link-color': '#F5222D',
          'border-radius-base': '4px',
        },
        javascriptEnabled: true,
      }
    }
  }
```
package.json
@@ -23,6 +23,9 @@
    "lodash.pick": "^4.4.0",
    "md5": "^2.2.1",
    "nprogress": "^0.2.0",
    "quill": "^2.0.3",
    "quill-image-drop-module": "^1.0.3",
    "quill-image-resize-module": "^3.0.0",
    "viser-vue": "^2.4.4",
    "vue": "^2.6.10",
    "vue-area-linkage": "^5.1.0",
@@ -33,12 +36,15 @@
    "vue-ls": "^3.2.0",
    "vue-photo-preview": "^1.1.3",
    "vue-print-nb-jeecg": "^1.0.9",
    "vue-quill-editor": "^3.0.6",
    "vue-router": "^3.0.1",
    "vue-splitpane": "^1.0.4",
    "vuedraggable": "^2.20.0",
    "vuex": "^3.1.0"
    "vuex": "^3.1.0",
    "wangeditor": "^4.7.15"
  },
  "devDependencies": {
    "@babel/plugin-proposal-class-properties": "^7.18.6",
    "@babel/polyfill": "^7.2.5",
    "@vue/cli-plugin-babel": "^3.3.0",
    "@vue/cli-plugin-eslint": "^3.3.0",
src/components/Editor.vue
对比新文件
@@ -0,0 +1,119 @@
<template>
  <div class="editor-container" :style="{ width: width }">
    <div ref="editor"></div>
  </div>
</template>
<script>
import E from 'wangeditor'
export default {
  name: 'Editor',
  props: {
    value: {
      type: String,
      default: ''
    },
    width: {
      type: String,
      default: '100%'
    },
    height: {
      type: Number,
      default: 300
    }
  },
  data() {
    return {
      editor: null,
      content: ''
    }
  },
  watch: {
    value: {
      handler(val) {
        if (val !== this.content && this.editor) {
          this.content = val || ''
          this.editor.txt.html(this.content)
        }
      },
      immediate: true
    }
  },
  mounted() {
    this.initEditor()
  },
  beforeDestroy() {
    if (this.editor) {
      this.editor.destroy()
      this.editor = null
    }
  },
  methods: {
    initEditor() {
      this.editor = new E(this.$refs.editor)
      // 配置菜单栏
      this.editor.config.menus = [
        'head',
        'bold',
        'fontSize',
        'fontName',
        'italic',
        'underline',
        'strikeThrough',
        'foreColor',
        'backColor',
        'link',
        'list',
        'justify',
        'quote',
        'emoticon',
        'image',
        'table',
        'code',
        'undo',
        'redo'
      ]
      // 配置编辑器高度
      this.editor.config.height = this.height
      // 配置图片上传
      this.editor.config.uploadImgServer = '/jshERP-boot/common/upload'
      this.editor.config.uploadFileName = 'file'
      this.editor.config.uploadImgHooks = {
        customInsert: (insertImgFn, result) => {
          if (result.code === 200) {
            insertImgFn(result.data.url)
          } else {
            this.$message.error('图片上传失败')
          }
        }
      }
      // 配置 onchange 回调函数
      this.editor.config.onchange = (html) => {
        this.content = html
        this.$emit('input', html)
        this.$emit('change', html)
      }
      // 创建编辑器
      this.editor.create()
      // 设置初始内容
      if (this.value) {
        this.editor.setHtml(this.value)
      }
    }
  }
}
</script>
<style scoped>
.editor-container {
  border: 1px solid #ccc;
  z-index: 100;
}
</style>
src/views/system/CloudContent.vue
对比新文件
@@ -0,0 +1,234 @@
<template>
  <a-row :gutter="24">
    <a-col :md="24">
      <a-card :style="cardStyle" :bordered="false">
        <!-- 查询区域 -->
        <div class="table-page-search-wrapper">
          <a-form layout="inline" @keyup.enter.native="searchQuery">
            <a-row :gutter="24">
              <a-col :md="6" :sm="24">
                <a-form-item label="标题" :labelCol="labelCol" :wrapperCol="wrapperCol">
                  <a-input placeholder="请输入标题查询" v-model="queryParam.title"></a-input>
                </a-form-item>
              </a-col>
              <a-col :md="6" :sm="24">
                <a-form-item label="内容类型" :labelCol="labelCol" :wrapperCol="wrapperCol">
                  <a-select placeholder="请选择内容类型" v-model="queryParam.type" allowClear>
                    <a-select-option value="privacy_policy">隐私政策</a-select-option>
                    <a-select-option value="user_guide">用户指南</a-select-option>
                  </a-select>
                </a-form-item>
              </a-col>
              <a-col :md="6" :sm="24">
                <a-form-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
                  <a-select placeholder="请选择状态" v-model="queryParam.status" allowClear>
                    <a-select-option :value="0">草稿</a-select-option>
                    <a-select-option :value="1">已发布</a-select-option>
                  </a-select>
                </a-form-item>
              </a-col>
              <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
                <a-col :md="6" :sm="24">
                  <a-button type="primary" @click="searchQuery">查询</a-button>
                  <a-button style="margin-left: 8px" @click="searchReset">重置</a-button>
                </a-col>
              </span>
            </a-row>
          </a-form>
        </div>
        <!-- 操作按钮区域 -->
        <div class="table-operator" style="margin-top: 5px">
          <a-button  type="primary" icon="plus" @click="handleAdd">新增</a-button>
          <a-button  type="primary" icon="delete" @click="batchDel">删除</a-button>
        </div>
        <!-- table区域-begin -->
        <div>
          <a-table
            ref="table"
            size="middle"
            bordered
            rowKey="id"
            :columns="columns"
            :dataSource="dataSource"
            :pagination="ipagination"
            :loading="loading"
            :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
            @change="handleTableChange">
            <span slot="action" slot-scope="text, record">
              <a @click="handleEdit(record)">编辑</a>
              <a-divider type="vertical" />
              <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
                <a>删除</a>
              </a-popconfirm>
            </span>
            <template slot="statusSlot" slot-scope="text">
              <a-tag :color="text === 1 ? 'green' : 'orange'">
                {{ text === 1 ? '已发布' : '草稿' }}
              </a-tag>
            </template>
            <template slot="typeSlot" slot-scope="text">
              {{ text === 'privacy_policy' ? '隐私政策' : '用户指南' }}
            </template>
          </a-table>
        </div>
        <!-- table区域-end -->
        <!-- 表单区域 -->
        <cloud-content-modal ref="modalForm" @ok="modalFormOk"></cloud-content-modal>
      </a-card>
    </a-col>
  </a-row>
</template>
<script>
import { JeecgListMixin } from '@/mixins/JeecgListMixin'
import CloudContentModal from './modules/CloudContentModal'
import { deleteAction, getAction } from '@/api/manage'
export default {
  name: "CloudContentList",
  mixins:[JeecgListMixin],
  components: {
    CloudContentModal
  },
  data () {
    return {
      description: '云内容管理页面',
      labelCol: {
        xs: { span: 24 },
        sm: { span: 5 },
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 },
      },
      // 查询条件
      queryParam: {
        title: '',
        type: '',
        status: undefined
      },
      // 表头
      columns: [
        {
          title: '#',
          dataIndex: '',
          key:'rowIndex',
          width:60,
          align:"center",
          customRender:function (t,r,index) {
            return parseInt(index)+1;
          }
        },
        {
          title: '操作',
          dataIndex: 'action',
          width:120,
          align:"center",
          scopedSlots: { customRender: 'action' }
        },
        {
          title: '标题',
          align:"left",
          dataIndex: 'title'
        },
        {
          title: '内容类型',
          align:"center",
          dataIndex: 'type',
          scopedSlots: { customRender: 'typeSlot' }
        },
        {
          title: '版本号',
          align:"center",
          dataIndex: 'version'
        },
        {
          title: '状态',
          align:"center",
          dataIndex: 'status',
          scopedSlots: { customRender: 'statusSlot' }
        },
        {
          title: '创建时间',
          align:"center",
          dataIndex: 'createTime',
          width: 180
        }
      ],
      url: {
        list: "/cloudContent/list",
        delete: "/cloudContent/delete",
        deleteBatch: "/cloudContent/deleteBatch",
        exportXlsUrl: "/cloudContent/exportXls",
        importExcelUrl: "/cloudContent/importExcel",
      },
      btnEnableList: [],
      cardStyle: {
        height: '100%'
      }
    }
  },
  computed: {
    importExcelUrl: function(){
      return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`;
    }
  },
  methods: {
    searchReset() {
      this.queryParam = {
        title: '',
        type: '',
        status: undefined
      }
      this.loadData(1);
    },
    handleEdit: function (record) {
      this.$refs.modalForm.edit(record);
      this.$refs.modalForm.title = "编辑";
      this.$refs.modalForm.disableSubmit = false;
      if(this.btnEnableList.indexOf(1)===-1) {
        this.$refs.modalForm.isReadOnly = true
      }
    },
    handleAdd: function () {
      this.$refs.modalForm.add();
      this.$refs.modalForm.title = "新增";
      this.$refs.modalForm.disableSubmit = false;
    },
    handleDelete(id) {
      deleteAction(this.url.delete, {id: id}).then((res) => {
        if (res.success) {
          this.$message.success(res.message);
          this.loadData();
        } else {
          this.$message.warning(res.message);
        }
      });
    },
    batchDel() {
      if (this.selectedRowKeys.length <= 0) {
        this.$message.warning('请选择一条记录!');
        return;
      }
      let ids = "";
      this.selectedRowKeys.forEach(function(val) {
        ids+=val+",";
      });
      ids = ids.substring(0,ids.length-1);
      deleteAction(this.url.deleteBatch, {ids: ids}).then((res) => {
        if (res.success) {
          this.$message.success(res.message);
          this.loadData();
          this.selectedRowKeys = [];
        } else {
          this.$message.warning(res.message);
        }
      });
    }
  }
}
</script>
<style scoped>
@import '~@assets/less/common.less'
</style>
src/views/system/SecurityList.vue
@@ -9,13 +9,22 @@
            <a-row :gutter="24">
              <a-col :md="6" :sm="24">
                <a-form-item label="关键词" :labelCol="labelCol" :wrapperCol="wrapperCol">
                  <a-input placeholder="请输入关键词查询" v-model="queryParam.name"></a-input>
                  <a-input placeholder="请输入关键词查询" v-model="queryParam.keyword"></a-input>
                </a-form-item>
              </a-col>
              <a-col :md="6" :sm="24">
                <a-form-item label="备注" :labelCol="labelCol" :wrapperCol="wrapperCol">
                  <a-input placeholder="请输入备注查询" v-model="queryParam.description"></a-input>
                </a-form-item>
                <a-form-item label="防护类型" :labelCol="labelCol" :wrapperCol="wrapperCol">
                    <a-select
                      optionFilterProp="children"
                      :dropdownMatchSelectWidth="false"
                      showSearch allow-clear style="width: 100%"
                      placeholder="请选择防护类型"
                      v-model="queryParam.type">
                      <a-select-option v-for="(type,index) in typeList" :value="type.itemValue" :key="index">
                        {{ type.itemText }}
                      </a-select-option>
                    </a-select>
                  </a-form-item>
              </a-col>
              <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
                <a-col :md="6" :sm="24">
@@ -28,10 +37,10 @@
        </div>
        <!-- 操作按钮区域 -->
        <div class="table-operator"  style="margin-top: 5px">
          <a-button v-if="btnEnableList.indexOf(1)>-1" @click="handleAdd" type="primary" icon="plus">新增</a-button>
          <a-button v-if="btnEnableList.indexOf(1)>-1" @click="batchDel" icon="delete">删除</a-button>
          <a-button v-if="btnEnableList.indexOf(1)>-1" @click="batchSetStatus(true)" icon="check-square">启用</a-button>
          <a-button v-if="btnEnableList.indexOf(1)>-1" @click="batchSetStatus(false)" icon="close-square">禁用</a-button>
          <a-button  @click="handleAdd" type="primary" icon="plus">新增</a-button>
          <a-button  @click="batchDel" icon="delete">删除</a-button>
          <a-button  @click="batchSetStatus(true)" icon="check-square">启用</a-button>
          <a-button  @click="batchSetStatus(false)" icon="close-square">禁用</a-button>
        </div>
        <!-- table区域-begin -->
        <div>
@@ -48,27 +57,26 @@
            :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
            @change="handleTableChange">
            <span slot="action" slot-scope="text, record">
              <a @click="handleSetFunction(record)">分配功能</a>
              <a-divider type="vertical" />
              <a @click="handleSetPushBtn(record.id, record.name)">分配按钮</a>
              <a-divider type="vertical" />
              <a @click="handleEdit(record)">编辑</a>
              <a-divider v-if="btnEnableList.indexOf(1)>-1" type="vertical" />
              <a-popconfirm v-if="btnEnableList.indexOf(1)>-1" title="确定删除吗?" @confirm="() => handleDelete(record.id)">
              <a-divider  type="vertical" />
              <a-popconfirm  title="确定删除吗?" @confirm="() => handleDelete(record.id)">
                <a>删除</a>
              </a-popconfirm>
              <a-modal v-model="roleModalVisible" title="操作提示" @ok="handleRoleTip(record)">
                <p>保存角色已经操作成功!现在继续<b>分配功能</b>吗?</p>
              </a-modal>
            </span>
            <span slot="typeTitle">
            <!-- <span slot="typeTitle">
              防护类型
              <a-tooltip title="1、全部数据-该角色对应的用户可以看到全部单据;2、本机构数据-该角色对应的用户可以看到自己所在机构的全部单据;
                3、个人数据-该角色对应的用户只可以看到自己的单据。单据是指采购入库、销售出库等">
              <a-tooltip title="">
                <a-icon type="question-circle" />
              </a-tooltip>
            </span>
            </span> -->
            <!-- 状态渲染模板 -->
            <template slot="type" slot-scope="type">
              <a-tag color="green">{{ getDictItemLabel(typeList,type) }}</a-tag>
            </template>
            <template slot="customRenderFlag" slot-scope="enabled">
              <a-tag v-if="enabled" color="green">启用</a-tag>
              <a-tag v-if="!enabled" color="orange">禁用</a-tag>
@@ -77,36 +85,34 @@
        </div>
        <!-- table区域-end -->
        <!-- 表单区域 -->
        <role-modal ref="modalForm" @ok="roleModalFormOk"></role-modal>
        <security-modal ref="modalForm" @ok="roleModalFormOk"></security-modal>
        <role-function-modal ref="roleFunctionModal" @ok="roleFunctionModalFormOk"></role-function-modal>
        <role-push-btn-modal ref="rolePushBtnModal" @ok="modalFormOk"></role-push-btn-modal>
        <a-modal v-model="roleFunctionModalVisible" title="操作提示" @ok="handleRoleFunctionTip">
          <p>分配功能已经操作成功!现在继续<b>分配按钮</b>吗?</p>
        </a-modal>
      </a-card>
    </a-col>
  </a-row>
</template>
<!-- f r o m 7 5  2 7 1  8 9 2 0 -->
<script>
  import RoleModal from './modules/RoleModal'
  import SecurityModal from './modules/SecurityModal'
  import RoleFunctionModal from './modules/RoleFunctionModal'
  import RolePushBtnModal from './modules/RolePushBtnModal'
  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
  import JDate from '@/components/jeecg/JDate'
  import {getAction,deleteAction,postAction } from '@/api/manage'
  export default {
    name: "RoleList",
    name: "SecurityList",
    mixins:[JeecgListMixin],
    components: {
      RoleModal,
      SecurityModal,
      RoleFunctionModal,
      RolePushBtnModal,
      JDate
    },
    data () {
      return {
        description: '角色管理页面',
        roleModalVisible: false,
        description: '高级安全防护管理页面',
        roleFunctionModalVisible: false,
        currentRoleId: '',
        labelCol: {
@@ -118,8 +124,8 @@
        },
        // 查询条件
        queryParam: {
          name: '',
          description: '',
          keyword: '',
          type: '',
        },
        // 表头
        columns: [
@@ -144,8 +150,9 @@
            title: '关键词', align:"left", dataIndex: 'keyword', width: 120
          },
          {
            align:"left", dataIndex: 'type', width: 100,
            slots: { title: 'typeTitle' }
            title:'    防护类型',align:"left", dataIndex: 'type', width: 100,
            slots: { title: 'typeTitle' },
            scopedSlots: { customRender: 'type' }
          },
          { title: '状态',dataIndex: 'status',width:60,align:"center",
            scopedSlots: { customRender: 'customRenderFlag' }
@@ -157,6 +164,7 @@
          deleteBatch: "/config-security/deleteBatch",
          batchSetStatusUrl: "/config-security/batchSetStatus"
        },
        typeList:[],
      }
    },
    computed: {
@@ -164,11 +172,56 @@
        return `${window._CONFIG['domianURL']}/${this.url.importExcelUrl}`;
      }
    },
    mounted(){
      this.loadDictData();
    },
    methods: {
      handleSetFunction(record) {
        this.$refs.roleFunctionModal.edit(record);
        this.$refs.roleFunctionModal.title = "分配功能给:" + record.name + "【分配之后请继续分配按钮】"
        this.$refs.roleFunctionModal.disableSubmit = false;
      searchQuery() {
        this.ipagination.current = 1;
        this.loadData();
      },
      loadData(arg) {
        //加载数据 若传入参数1则加载第一页的内容
        // this.ipagination.current = 1;
        let params = this.queryParam
        params.currentPage = this.ipagination.current;
        params.pageSize = this.ipagination.pageSize;
        this.loading = true;
        getAction(this.url.list, params).then((res) => {
          if (res.code===200) {
            this.dataSource = res.data.rows;
            this.ipagination.total = res.data.total;
            this.tableAddTotalRow(this.columns, this.dataSource)
            this.realityPriceTotal = res.data.realityPriceTotal
          } else if(res.code===510){
            this.$message.warning(res.data)
          } else {
            this.$message.warning(res.data.message)
          }
          this.loading = false;
        })
      },
      loadDictData() {
        // 安全防护类型
        var dictCode='securityType'
        getAction(`/sysDict/items/dict-code/${dictCode}`).then((res)=>{
          if(res.code === 200){
            this.typeList = res.data;
          }else{
            this.$message.info(res.data);
          }
        })
      },
      getDictItemLabel(list, value) {
        const item = list.find(item => item.itemValue === value);
        return item ? item.itemText : null;
      },
      handleSetPushBtn(roleId, roleName) {
        this.$refs.rolePushBtnModal.edit(roleId);
@@ -178,7 +231,6 @@
      roleModalFormOk() {
        //重载列表
        this.loadData()
        this.roleModalVisible = true
      },
      roleFunctionModalFormOk(id) {
        //重载列表
@@ -186,37 +238,84 @@
        this.roleFunctionModalVisible = true
        this.currentRoleId = id
      },
      handleRoleTip(record) {
        if(record) {
          this.roleModalVisible = false
          this.handleSetFunction(record)
        }
      },
      handleRoleFunctionTip() {
        if(this.currentRoleId) {
          this.roleFunctionModalVisible = false
          let roleName = ''
          for (let i = 0; i < this.dataSource.length; i++) {
            if(this.dataSource[i].id == this.currentRoleId) {
              roleName = this.dataSource[i].name
            }
          }
          this.handleSetPushBtn(this.currentRoleId, roleName)
        }
      },
      handleAdd: function () {
        this.$refs.modalForm.add();
        this.$refs.modalForm.title = "新增【保存之后请继续分配功能】";
        this.$refs.modalForm.title = "新增";
        this.$refs.modalForm.disableSubmit = false;
      },
      handleEdit: function (record) {
        console.log("edit", record);
        this.$refs.modalForm.edit(record);
        this.$refs.modalForm.title = "编辑【保存之后请继续分配功能】";
        this.$refs.modalForm.title = "编辑";
        this.$refs.modalForm.disableSubmit = false;
        if(this.btnEnableList.indexOf(1)===-1) {
          this.$refs.modalForm.isReadOnly = true
        }
      }
      },
      handleDelete(id) {
        deleteAction(this.url.delete+`/${id}`, {id: id}).then((res) => {
          if (res.code === 200) {
            this.loadData();
            this.$message.success(res.message);
          } else {
            this.$message.warning(res.message);
          }
        });
      },
      batchDel() {
        if (this.selectedRowKeys.length <= 0) {
          this.$message.warning('请选择一条记录!');
          return;
        }
        let ids = "";
        this.selectedRowKeys.forEach(function(val) {
          ids+=val+",";
        });
        ids = ids.substring(0,ids.length-1);
        deleteAction(this.url.deleteBatch, {ids: ids}).then((res) => {
          if(res.code === 200){
            this.$message.success(res.msg);
            this.loadData();
            this.selectedRowKeys = [];
          } else {
            this.$message.warning(res.msg);
          }
        });
      },
       batchSetStatus: function (status) {
            if(!this.url.batchSetStatusUrl){
              this.$message.error("请设置url.batchSetStatusUrl属性!")
              return
            }
            if (this.selectedRowKeys.length <= 0) {
              this.$message.warning('请选择一条记录!');
              return;
            } else {
              var ids = "";
              for (var a = 0; a < this.selectedRowKeys.length; a++) {
                ids += this.selectedRowKeys[a] + ",";
              }
              var that = this;
              this.$confirm({
                title: "确认操作",
                content: "是否操作选中数据?",
                onOk: function () {
                  that.loading = true;
                  postAction(that.url.batchSetStatusUrl, {status: status, ids: ids}).then((res) => {
                    if(res.code === 200){
                      that.loadData()
                    } else {
                      that.$message.warning(res.data.message);
                    }
                  }).finally(() => {
                    that.loading = false;
                  });
                }
              });
            }
          },
    }
  }
</script>
src/views/system/SysDictList.vue
对比新文件
@@ -0,0 +1,227 @@
<template>
  <a-row :gutter="24">
    <a-col :md="24">
      <a-card :style="cardStyle" :bordered="false">
        <!-- 查询区域 -->
        <div class="table-page-search-wrapper">
          <a-form layout="inline" @keyup.enter.native="searchQuery">
            <a-row :gutter="24">
              <a-col :md="6" :sm="24">
                <a-form-item label="字典编码" :labelCol="labelCol" :wrapperCol="wrapperCol">
                  <a-input placeholder="请输入字典编码" v-model="queryParam.dictCode"></a-input>
                </a-form-item>
              </a-col>
              <a-col :md="6" :sm="24">
                <a-form-item label="字典名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
                  <a-input placeholder="请输入字典名称" v-model="queryParam.dictName"></a-input>
                </a-form-item>
              </a-col>
              <a-col :md="6" :sm="24">
                <a-form-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
                  <a-select placeholder="请选择状态" v-model="queryParam.status" allowClear>
                    <a-select-option :value="0">停用</a-select-option>
                    <a-select-option :value="1">启用</a-select-option>
                  </a-select>
                </a-form-item>
              </a-col>
              <span style="float: left;overflow: hidden;" class="table-page-search-submitButtons">
                <a-col :md="6" :sm="24">
                  <a-button type="primary" @click="searchQuery">查询</a-button>
                  <a-button style="margin-left: 8px" @click="searchReset">重置</a-button>
                </a-col>
              </span>
            </a-row>
          </a-form>
        </div>
        <!-- 操作按钮区域 -->
        <div class="table-operator" style="margin-top: 5px">
          <a-button type="primary" icon="plus" @click="handleAdd">新增</a-button>
          <a-button type="primary" icon="delete" @click="batchDel">删除</a-button>
        </div>
        <!-- table区域-begin -->
        <div>
          <a-table
            ref="table"
            size="middle"
            bordered
            rowKey="id"
            :columns="columns"
            :dataSource="dataSource"
            :pagination="ipagination"
            :loading="loading"
            :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange}"
            @change="handleTableChange">
            <span slot="action" slot-scope="text, record">
              <a @click="handleEdit(record)">编辑</a>
              <a-divider type="vertical" />
              <a @click="handleItems(record)">字典项</a>
              <a-divider type="vertical" />
              <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
                <a>删除</a>
              </a-popconfirm>
            </span>
            <template slot="statusSlot" slot-scope="text">
              <a-tag :color="text === 1 ? 'green' : 'orange'">
                {{ text === 1 ? '启用' : '停用' }}
              </a-tag>
            </template>
          </a-table>
        </div>
        <!-- table区域-end -->
        <!-- 表单区域 -->
        <sys-dict-modal ref="modalForm" @ok="modalFormOk"></sys-dict-modal>
        <sys-dict-item-modal ref="itemModalForm" @ok="modalFormOk"></sys-dict-item-modal>
      </a-card>
    </a-col>
  </a-row>
</template>
<script>
  import { JeecgListMixin } from '@/mixins/JeecgListMixin'
  import SysDictModal from './modules/SysDictModal'
  import SysDictItemModal from './modules/SysDictItemModal'
  import { deleteAction } from '@/api/manage'
  export default {
    name: "SysDictList",
    mixins:[JeecgListMixin],
    components: {
      SysDictModal,
      SysDictItemModal
    },
    data () {
      return {
        description: '字典管理页面',
        labelCol: {
          xs: { span: 24 },
          sm: { span: 5 },
        },
        wrapperCol: {
          xs: { span: 24 },
          sm: { span: 16 },
        },
        // 查询条件
        queryParam: {
          dictCode: '',
          dictName: '',
          status: undefined
        },
        // 表头
        columns: [
          {
            title: '#',
            dataIndex: '',
            key:'rowIndex',
            width:60,
            align:"center",
            customRender:function (t,r,index) {
              return parseInt(index)+1;
            }
          },
          {
            title: '操作',
            dataIndex: 'action',
            width:150,
            align:"center",
            scopedSlots: { customRender: 'action' }
          },
          {
            title: '字典编码',
            align:"left",
            dataIndex: 'dictCode'
          },
          {
            title: '字典名称',
            align:"left",
            dataIndex: 'dictName'
          },
          {
            title: '描述',
            align:"left",
            dataIndex: 'description'
          },
          {
            title: '状态',
            align:"center",
            dataIndex: 'status',
            scopedSlots: { customRender: 'statusSlot' }
          },
          {
            title: '创建时间',
            align:"center",
            dataIndex: 'createTime',
            width: 180
          }
        ],
        url: {
          list: "/sysDict/list",
          delete: "/sysDict/delete",
          deleteBatch: "/sysDict/deleteBatch"
        },
        btnEnableList: [],
        cardStyle: {
          height: '100%'
        }
      }
    },
    methods: {
      searchReset() {
        this.queryParam = {
          dictCode: '',
          dictName: '',
          status: undefined
        }
        this.loadData(1);
      },
      handleEdit: function (record) {
        this.$refs.modalForm.edit(record);
        this.$refs.modalForm.title = "编辑";
        this.$refs.modalForm.disableSubmit = false;
      },
      handleAdd: function () {
        this.$refs.modalForm.add();
        this.$refs.modalForm.title = "新增";
        this.$refs.modalForm.disableSubmit = false;
      },
      handleItems: function (record) {
        this.$refs.itemModalForm.show(record);
        this.$refs.itemModalForm.title = "字典项管理";
        this.$refs.itemModalForm.disableSubmit = false;
      },
      handleDelete(id) {
        deleteAction(this.url.delete, {id: id}).then((res) => {
          if (res.success) {
            this.$message.success(res.message);
            this.loadData();
          } else {
            this.$message.warning(res.message);
          }
        });
      },
      batchDel() {
        if (this.selectedRowKeys.length <= 0) {
          this.$message.warning('请选择一条记录!');
          return;
        }
        let ids = "";
        this.selectedRowKeys.forEach(function(val) {
          ids+=val+",";
        });
        ids = ids.substring(0,ids.length-1);
        deleteAction(this.url.deleteBatch, {ids: ids}).then((res) => {
          if (res.success) {
            this.$message.success(res.message);
            this.loadData();
            this.selectedRowKeys = [];
          } else {
            this.$message.warning(res.message);
          }
        });
      }
    }
  }
</script>
<style scoped>
  @import '~@assets/less/common.less'
</style>
src/views/system/modules/CloudContentModal.vue
对比新文件
@@ -0,0 +1,154 @@
<template>
  <div ref="container">
    <a-modal
      :title="title"
      :width="1200"
      :visible="visible"
      :confirmLoading="confirmLoading"
      :getContainer="() => $refs.container"
      :maskStyle="{'top':'93px','left':'154px'}"
      :wrapClassName="wrapClassNameInfo()"
      :mask="isDesktop()"
      :maskClosable="false"
      @ok="handleOk"
      @cancel="handleCancel"
      cancelText="取消"
      okText="保存"
      style="top:10%;height: 80%;">
      <a-spin :spinning="confirmLoading">
        <a-form :form="form" id="cloudContentModal">
          <a-row class="form-row" :gutter="24">
            <a-col :span="12">
              <a-form-item label="标题" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-input placeholder="请输入标题" v-decorator="['title', validatorRules.title]" />
              </a-form-item>
            </a-col>
            <a-col :span="12">
              <a-form-item label="内容类型" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-select placeholder="请选择内容类型" v-decorator="['type', validatorRules.type]">
                  <a-select-option value="privacy_policy">隐私政策</a-select-option>
                  <a-select-option value="user_guide">用户指南</a-select-option>
                </a-select>
              </a-form-item>
            </a-col>
            <a-col :span="12">
              <a-form-item label="版本号" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-input placeholder="请输入版本号" v-decorator="['version', validatorRules.version]" />
              </a-form-item>
            </a-col>
            <a-col :span="12">
              <a-form-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-radio-group v-decorator="['status', {initialValue: 0}]">
                  <a-radio :value="0">草稿</a-radio>
                  <a-radio :value="1">发布</a-radio>
                </a-radio-group>
              </a-form-item>
            </a-col>
            <a-col :span="24">
              <a-form-item label="内容" :labelCol="{span: 2}" :wrapperCol="{span: 22}">
                <editor v-decorator="['content', validatorRules.content]" :height="400" />
              </a-form-item>
            </a-col>
          </a-row>
        </a-form>
      </a-spin>
    </a-modal>
  </div>
</template>
<script>
import { mixinDevice } from '@/utils/mixin'
import Editor from '@/components/Editor'
import pick from 'lodash.pick'
export default {
  name: "CloudContentModal",
  mixins: [mixinDevice],
  components: {
    Editor
  },
  data () {
    return {
      title: "操作",
      visible: false,
      model: {},
      labelCol: {
        xs: { span: 24 },
        sm: { span: 5 },
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 },
      },
      confirmLoading: false,
      form: this.$form.createForm(this),
      validatorRules: {
        title: {
          rules: [{ required: true, message: '请输入标题!' }]
        },
        type: {
          rules: [{ required: true, message: '请选择内容类型!' }]
        },
        version: {
          rules: [{ required: true, message: '请输入版本号!' }]
        },
        content: {
          rules: [{ required: true, message: '请输入内容!' }]
        }
      }
    }
  },
  methods: {
    add () {
      this.edit({})
    },
    edit (record) {
      this.form.resetFields()
      this.model = Object.assign({}, record)
      this.visible = true
      this.$nextTick(() => {
        this.form.setFieldsValue(pick(this.model,'title', 'type', 'version', 'content', 'status'))
      })
    },
    close () {
      this.$emit('close')
      this.visible = false
    },
    handleOk () {
      const that = this
      this.form.validateFields((err, values) => {
        if (!err) {
          that.confirmLoading = true
          let formData = Object.assign(this.model, values)
          let obj
          if(!this.model.id){
            obj = this.$http.post('/cloudContent', formData)
          }else{
            obj = this.$http.put('/cloudContent', formData)
          }
          obj.then((res)=>{
            if(res.code === 200){
              that.$message.success(res.msg)
              that.$emit('ok')
            }else{
              that.$message.warning(res.msg)
            }
          }).finally(() => {
            that.confirmLoading = false
            that.close()
          })
        }
      })
    },
    handleCancel () {
      this.close()
    }
  }
}
</script>
<style lang="less" scoped>
.form-row {
  padding: 0 24px;
}
</style>
src/views/system/modules/SecurityModal.vue
对比新文件
@@ -0,0 +1,173 @@
<template>
  <div ref="container">
    <a-modal
      :title="title"
      :width="800"
      :visible="visible"
      :confirmLoading="confirmLoading"
      :getContainer="() => $refs.container"
      :maskStyle="{'top':'93px','left':'154px'}"
      :wrapClassName="wrapClassNameInfo()"
      :mask="isDesktop()"
      :maskClosable="false"
      @ok="handleOk"
      @cancel="handleCancel"
      cancelText="取消"
      okText="保存">
      <a-spin :spinning="confirmLoading">
        <a-form :form="form">
          <a-row class="form-row" :gutter="24">
            <a-col :span="24">
              <a-form-item label="关键词" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-input placeholder="请输入关键词" v-decorator="['keyword', validatorRules.keyword]" />
              </a-form-item>
            </a-col>
            <a-col :span="24">
              <a-form-item label="防护类型" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <!-- <a-input placeholder="请输入防护类型" v-decorator="['type', validatorRules.type]" /> -->
                <a-select
                      optionFilterProp="children"
                      :dropdownMatchSelectWidth="false"
                      showSearch allow-clear style="width: 100%"
                      placeholder="请选择防护类型"
                      v-decorator="['type', validatorRules.type]"
                      >
                      <a-select-option v-for="(type,index) in typeList" :value="type.itemValue" :key="index">
                        {{ type.itemText }}
                      </a-select-option>
                    </a-select>
              </a-form-item>
            </a-col>
            <a-col :span="24">
              <a-form-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-radio-group v-decorator="['status', {initialValue: 1}]">
                  <a-radio :value="1">启用</a-radio>
                  <a-radio :value="0">禁用</a-radio>
                </a-radio-group>
              </a-form-item>
            </a-col>
          </a-row>
        </a-form>
      </a-spin>
    </a-modal>
  </div>
</template>
<script>
  import { mixinDevice } from '@/utils/mixin'
  import { postAction, putAction,getAction } from '@/api/manage'
  import pick from 'lodash.pick'
  export default {
    name: "SysDictModal",
    mixins: [mixinDevice],
    data () {
      return {
        title:"操作",
        visible: false,
        model: {},
        labelCol: {
          xs: { span: 24 },
          sm: { span: 5 },
        },
        wrapperCol: {
          xs: { span: 24 },
          sm: { span: 16 },
        },
        confirmLoading: false,
        form: this.$form.createForm(this),
        validatorRules:{
          keyword: {
            rules: [{
              required: true,
              message: '请输入关键词!'
            },
            {
              max: 50,
              message: '关键词长度不能超过50个字符!'
            }
          ]
          },
          type: {
            rules: [{
              required: true,
              message: '请输入防护类型!'
            }]
          }
        },
        url: {
          add: "/config-security",
          edit: "/config-security"
        },
        typeList:[],
      }
    },
    mounted(){
      this.loadDictData();
    },
    methods: {
      loadDictData() {
        // 安全防护类型
        var dictCode='securityType'
        getAction(`/sysDict/items/dict-code/${dictCode}`).then((res)=>{
          if(res.code === 200){
            this.typeList = res.data;
          }else{
            this.$message.info(res.data);
          }
        })
      },
      add () {
        this.edit({})
      },
      edit (record) {
        debugger;
        this.form.resetFields()
        this.model = Object.assign({}, record)
        this.visible = true
        this.$nextTick(() => {
          this.form.setFieldsValue(pick(this.model,'keyword','type','status'))
        })
      },
      close () {
        this.$emit('close')
        this.visible = false
      },
      handleOk () {
        const that = this
        this.form.validateFields((err, values) => {
          if (!err) {
            that.confirmLoading = true
            let formData = Object.assign(this.model, values)
            let obj
            if(!this.model.id){
              obj = postAction(this.url.add, formData)
            }else{
              obj = putAction(this.url.edit, formData)
            }
            obj.then((res)=>{
              if(res.code === 200){
                that.$message.success(res.msg)
                that.$emit('ok')
              }else{
                that.$message.warning(res.msg)
              }
            }).finally(() => {
              that.confirmLoading = false
              that.close()
            })
          }
        })
      },
      handleCancel () {
        this.close()
      }
    }
  }
</script>
<style lang="less" scoped>
  .form-row {
    padding: 0 24px;
  }
</style>
src/views/system/modules/SysDictItemModal.vue
对比新文件
@@ -0,0 +1,267 @@
<template>
  <div ref="container">
    <a-modal
      :title="title"
      :width="1000"
      :visible="visible"
      :confirmLoading="confirmLoading"
      :getContainer="() => $refs.container"
      :maskStyle="{'top':'93px','left':'154px'}"
      :wrapClassName="wrapClassNameInfo()"
      :mask="isDesktop()"
      :maskClosable="false"
      @ok="handleOk"
      @cancel="handleCancel"
      cancelText="关闭">
      <template slot="footer">
        <a-button key="back" @click="handleCancel">关闭</a-button>
      </template>
      <a-card :bordered="false">
        <!-- 操作按钮区域 -->
        <div class="table-operator">
          <a-button type="primary" icon="plus" @click="handleAdd">新增</a-button>
        </div>
        <!-- table区域-begin -->
        <div>
          <a-table
            ref="table"
            size="middle"
            bordered
            rowKey="id"
            :columns="columns"
            :dataSource="dataSource"
            :pagination="false"
            :loading="loading">
            <span slot="action" slot-scope="text, record">
              <a @click="handleEdit(record)">编辑</a>
              <a-divider type="vertical" />
              <a-popconfirm title="确定删除吗?" @confirm="() => handleDelete(record.id)">
                <a>删除</a>
              </a-popconfirm>
            </span>
            <template slot="statusSlot" slot-scope="text">
              <a-tag :color="text === 1 ? 'green' : 'orange'">
                {{ text === 1 ? '启用' : '停用' }}
              </a-tag>
            </template>
          </a-table>
        </div>
        <!-- table区域-end -->
      </a-card>
      <a-modal
        :title="itemTitle"
        :width="600"
        :visible="itemVisible"
        :confirmLoading="itemConfirmLoading"
        @ok="handleItemOk"
        @cancel="handleItemCancel"
        cancelText="取消"
        okText="保存">
        <a-form :form="itemForm">
          <a-form-item label="字典项文本" :labelCol="labelCol" :wrapperCol="wrapperCol">
            <a-input placeholder="请输入字典项文本" v-decorator="['itemText', validatorRules.itemText]" />
          </a-form-item>
          <a-form-item label="字典项值" :labelCol="labelCol" :wrapperCol="wrapperCol">
            <a-input placeholder="请输入字典项值" v-decorator="['itemValue', validatorRules.itemValue]" />
          </a-form-item>
          <a-form-item label="描述" :labelCol="labelCol" :wrapperCol="wrapperCol">
            <a-textarea placeholder="请输入描述" v-decorator="['description']" :rows="2" />
          </a-form-item>
          <a-form-item label="排序" :labelCol="labelCol" :wrapperCol="wrapperCol">
            <a-input-number placeholder="请输入排序" v-decorator="['sortOrder', {initialValue: 0}]" :min="0" style="width: 100%" />
          </a-form-item>
          <a-form-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
            <a-radio-group v-decorator="['status', {initialValue: 1}]">
              <a-radio :value="1">启用</a-radio>
              <a-radio :value="0">停用</a-radio>
            </a-radio-group>
          </a-form-item>
        </a-form>
      </a-modal>
    </a-modal>
  </div>
</template>
<script>
  import { mixinDevice } from '@/utils/mixin'
  import { getAction, postAction, putAction, deleteAction } from '@/api/manage'
  import pick from 'lodash.pick'
  export default {
    name: "SysDictItemModal",
    mixins: [mixinDevice],
    data () {
      return {
        title:"字典项管理",
        visible: false,
        model: {},
        labelCol: {
          xs: { span: 24 },
          sm: { span: 5 },
        },
        wrapperCol: {
          xs: { span: 24 },
          sm: { span: 16 },
        },
        confirmLoading: false,
        loading: false,
        dataSource: [],
        // 字典项表单相关
        itemTitle: "",
        itemVisible: false,
        itemConfirmLoading: false,
        itemModel: {},
        itemForm: this.$form.createForm(this),
        validatorRules: {
          itemText: {
            rules: [{
              required: true,
              message: '请输入字典项文本!'
            }]
          },
          itemValue: {
            rules: [{
              required: true,
              message: '请输入字典项值!'
            }]
          }
        },
        // 表头
        columns: [
          {
            title: '#',
            dataIndex: '',
            key:'rowIndex',
            width:60,
            align:"center",
            customRender:function (t,r,index) {
              return parseInt(index)+1;
            }
          },
          {
            title: '操作',
            dataIndex: 'action',
            width:120,
            align:"center",
            scopedSlots: { customRender: 'action' }
          },
          {
            title: '文本',
            align:"left",
            dataIndex: 'itemText'
          },
          {
            title: '值',
            align:"left",
            dataIndex: 'itemValue'
          },
          {
            title: '描述',
            align:"left",
            dataIndex: 'description'
          },
          {
            title: '排序',
            align:"center",
            dataIndex: 'sortOrder',
            width: 80
          },
          {
            title: '状态',
            align:"center",
            dataIndex: 'status',
            width: 80,
            scopedSlots: { customRender: 'statusSlot' }
          }
        ]
      }
    },
    methods: {
      show (record) {
        this.model = Object.assign({}, record)
        this.visible = true
        this.loadData()
      },
      loadData () {
        this.loading = true
        getAction(`/sysDict/items/${this.model.id}`).then((res) => {
          if (res.code === 200) {
            this.dataSource = res.data
          }
          this.loading = false
        })
      },
      handleAdd () {
        this.itemTitle = "新增字典项"
        this.itemForm.resetFields()
        this.itemModel = {}
        this.itemVisible = true
      },
      handleEdit (record) {
        this.itemTitle = "编辑字典项"
        this.itemForm.resetFields()
        this.itemModel = Object.assign({}, record)
        this.itemVisible = true
        this.$nextTick(() => {
          this.itemForm.setFieldsValue(pick(this.itemModel,'itemText','itemValue','description','sortOrder','status'))
        })
      },
      handleDelete (id) {
        deleteAction(`/sysDict/item/${id}`).then((res) => {
          if (res.code === 200) {
            this.$message.success(res.msg)
            this.loadData()
          } else {
            this.$message.warning(res.msg)
          }
        })
      },
      handleItemOk () {
        const that = this
        this.itemForm.validateFields((err, values) => {
          if (!err) {
            that.itemConfirmLoading = true
            let formData = Object.assign(this.itemModel, values)
            formData.dictId = this.model.id
            let obj
            if(!this.itemModel.id){
              obj = postAction('/sysDict/item', formData)
            }else{
              obj = putAction('/sysDict/item', formData)
            }
            obj.then((res)=>{
              if(res.code === 200){
                that.$message.success(res.msg)
                that.loadData()
                that.itemVisible = false
              }else{
                that.$message.warning(res.msg)
              }
            }).finally(() => {
              that.itemConfirmLoading = false
            })
          }
        })
      },
      handleItemCancel () {
        this.itemVisible = false
      },
      handleCancel () {
        this.close()
      },
      close () {
        this.$emit('close')
        this.visible = false
      }
    }
  }
</script>
<style lang="less" scoped>
  .table-operator {
    margin-bottom: 18px;
  }
</style>
src/views/system/modules/SysDictModal.vue
对比新文件
@@ -0,0 +1,146 @@
<template>
  <div ref="container">
    <a-modal
      :title="title"
      :width="800"
      :visible="visible"
      :confirmLoading="confirmLoading"
      :getContainer="() => $refs.container"
      :maskStyle="{'top':'93px','left':'154px'}"
      :wrapClassName="wrapClassNameInfo()"
      :mask="isDesktop()"
      :maskClosable="false"
      @ok="handleOk"
      @cancel="handleCancel"
      cancelText="取消"
      okText="保存">
      <a-spin :spinning="confirmLoading">
        <a-form :form="form">
          <a-row class="form-row" :gutter="24">
            <a-col :span="12">
              <a-form-item label="字典编码" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-input placeholder="请输入字典编码" v-decorator="['dictCode', validatorRules.dictCode]" />
              </a-form-item>
            </a-col>
            <a-col :span="12">
              <a-form-item label="字典名称" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-input placeholder="请输入字典名称" v-decorator="['dictName', validatorRules.dictName]" />
              </a-form-item>
            </a-col>
            <a-col :span="24">
              <a-form-item label="描述" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-textarea placeholder="请输入描述" v-decorator="['description']" :rows="2" />
              </a-form-item>
            </a-col>
            <a-col :span="12">
              <a-form-item label="状态" :labelCol="labelCol" :wrapperCol="wrapperCol">
                <a-radio-group v-decorator="['status', {initialValue: 1}]">
                  <a-radio :value="1">启用</a-radio>
                  <a-radio :value="0">停用</a-radio>
                </a-radio-group>
              </a-form-item>
            </a-col>
          </a-row>
        </a-form>
      </a-spin>
    </a-modal>
  </div>
</template>
<script>
  import { mixinDevice } from '@/utils/mixin'
  import { postAction, putAction } from '@/api/manage'
  import pick from 'lodash.pick'
  export default {
    name: "SysDictModal",
    mixins: [mixinDevice],
    data () {
      return {
        title:"操作",
        visible: false,
        model: {},
        labelCol: {
          xs: { span: 24 },
          sm: { span: 5 },
        },
        wrapperCol: {
          xs: { span: 24 },
          sm: { span: 16 },
        },
        confirmLoading: false,
        form: this.$form.createForm(this),
        validatorRules:{
          dictCode: {
            rules: [{
              required: true,
              message: '请输入字典编码!'
            }]
          },
          dictName: {
            rules: [{
              required: true,
              message: '请输入字典名称!'
            }]
          }
        },
        url: {
          add: "/sysDict",
          edit: "/sysDict"
        }
      }
    },
    methods: {
      add () {
        this.edit({})
      },
      edit (record) {
        this.form.resetFields()
        this.model = Object.assign({}, record)
        this.visible = true
        this.$nextTick(() => {
          this.form.setFieldsValue(pick(this.model,'dictCode','dictName','description','status'))
        })
      },
      close () {
        this.$emit('close')
        this.visible = false
      },
      handleOk () {
        const that = this
        this.form.validateFields((err, values) => {
          if (!err) {
            that.confirmLoading = true
            let formData = Object.assign(this.model, values)
            let obj
            if(!this.model.id){
              obj = postAction(this.url.add, formData)
            }else{
              obj = putAction(this.url.edit, formData)
            }
            obj.then((res)=>{
              if(res.code === 200){
                that.$message.success(res.msg)
                that.$emit('ok')
              }else{
                that.$message.warning(res.msg)
              }
            }).finally(() => {
              that.confirmLoading = false
              that.close()
            })
          }
        })
      },
      handleCancel () {
        this.close()
      }
    }
  }
</script>
<style lang="less" scoped>
  .form-row {
    padding: 0 24px;
  }
</style>