From a35f4b4d0c555493cc464bfd36d037230547f1aa Mon Sep 17 00:00:00 2001
From: tj <1378534974@qq.com>
Date: 星期四, 20 三月 2025 09:44:44 +0800
Subject: [PATCH] 1.高级安全防护
---
src/views/system/modules/SysDictItemModal.vue | 267 +++++++++
src/views/system/modules/SecurityModal.vue | 173 ++++++
package.json | 8
src/views/system/SecurityList.vue | 219 +++++--
src/views/system/modules/CloudContentModal.vue | 154 +++++
src/views/system/modules/SysDictModal.vue | 146 +++++
src/components/Editor.vue | 119 ++++
src/views/system/SysDictList.vue | 227 ++++++++
src/views/system/CloudContent.vue | 234 ++++++++
README.md | 80 ++
10 files changed, 1,564 insertions(+), 63 deletions(-)
diff --git a/README.md b/README.md
index 5c5dadb..08acd7c 100644
--- a/README.md
+++ b/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,
+ }
+ }
+ }
+```
+
+
diff --git a/package.json b/package.json
index c8d1e65..01a13a4 100644
--- a/package.json
+++ b/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",
diff --git a/src/components/Editor.vue b/src/components/Editor.vue
new file mode 100644
index 0000000..1bf2afb
--- /dev/null
+++ b/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>
\ No newline at end of file
diff --git a/src/views/system/CloudContent.vue b/src/views/system/CloudContent.vue
new file mode 100644
index 0000000..6c6622e
--- /dev/null
+++ b/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>
\ No newline at end of file
diff --git a/src/views/system/SecurityList.vue b/src/views/system/SecurityList.vue
index 24a044c..912acb2 100644
--- a/src/views/system/SecurityList.vue
+++ b/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>
diff --git a/src/views/system/SysDictList.vue b/src/views/system/SysDictList.vue
new file mode 100644
index 0000000..8c2518e
--- /dev/null
+++ b/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>
\ No newline at end of file
diff --git a/src/views/system/modules/CloudContentModal.vue b/src/views/system/modules/CloudContentModal.vue
new file mode 100644
index 0000000..4d8f42b
--- /dev/null
+++ b/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>
\ No newline at end of file
diff --git a/src/views/system/modules/SecurityModal.vue b/src/views/system/modules/SecurityModal.vue
new file mode 100644
index 0000000..e49166b
--- /dev/null
+++ b/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>
\ No newline at end of file
diff --git a/src/views/system/modules/SysDictItemModal.vue b/src/views/system/modules/SysDictItemModal.vue
new file mode 100644
index 0000000..8fa48f2
--- /dev/null
+++ b/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>
\ No newline at end of file
diff --git a/src/views/system/modules/SysDictModal.vue b/src/views/system/modules/SysDictModal.vue
new file mode 100644
index 0000000..944e3ed
--- /dev/null
+++ b/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>
\ No newline at end of file
--
Gitblit v1.9.3