Merge remote-tracking branch 'origin/main'

main
zxf 5 days ago
commit 78f926e3e6

@ -1,306 +0,0 @@
<template>
<div class="divBox">
<el-form :inline="true" :model="dataForm" @keyup.enter.native="getDataList()">
<el-form-item label="字典编码">
<el-input v-model="dataForm.dictCode" placeholder="请输入字典编码" clearable></el-input>
</el-form-item>
<el-form-item label="字典排序">
<el-input v-model="dataForm.dictSort" placeholder="请输入字典排序" clearable></el-input>
</el-form-item>
<el-form-item label="字典标签">
<el-input v-model="dataForm.dictLabel" placeholder="请输入字典标签" clearable></el-input>
</el-form-item>
<el-form-item label="字典键值">
<el-input v-model="dataForm.dictValue" placeholder="请输入字典键值" clearable></el-input>
</el-form-item>
<el-form-item label="字典类型">
<el-input v-model="dataForm.dictType" placeholder="请输入字典类型" clearable></el-input>
</el-form-item>
<el-form-item label="样式属性(其他样式扩展)">
<el-input v-model="dataForm.cssClass" placeholder="请输入样式属性(其他样式扩展)" clearable></el-input>
</el-form-item>
<el-form-item label="表格回显样式">
<el-input v-model="dataForm.listClass" placeholder="请输入表格回显样式" clearable></el-input>
</el-form-item>
<el-form-item label="是否默认Y是 N否">
<el-input v-model="dataForm.isDefault" placeholder="请输入是否默认Y是 N否" clearable></el-input>
</el-form-item>
<el-form-item label="状态0正常 1停用">
<el-input v-model="dataForm.status" placeholder="请输入状态0正常 1停用" clearable></el-input>
</el-form-item>
<el-form-item label="备注">
<el-input v-model="dataForm.remark" placeholder="请输入备注" clearable></el-input>
</el-form-item>
<el-form-item label="字典代码">
<el-input v-model="dataForm.dataCode" placeholder="请输入字典代码" clearable></el-input>
</el-form-item>
<el-form-item>
<el-button @click="getDataList()"></el-button>
<el-button @click="resetForm()"></el-button>
<el-button v-hasPermi="['autogencode:sysdictdata:save']" type="primary" @click="addOrUpdateHandle()"></el-button>
<el-button v-hasPermi="['autogencode:sysdictdata:delete']" type="danger" @click="deleteHandle()" :disabled="dataListSelections.length <= 0"></el-button>
</el-form-item>
</el-form>
<el-table
:data="dataList"
border
v-loading="dataListLoading"
@selection-change="selectionChangeHandle"
style="width: 100%;">
<el-table-column
type="selection"
header-align="center"
align="center"
width="50">
</el-table-column>
<el-table-column
prop="dictCode"
header-align="center"
align="center"
label="字典编码">
</el-table-column>
<el-table-column
prop="dictSort"
header-align="center"
align="center"
label="字典排序">
</el-table-column>
<el-table-column
prop="dictLabel"
header-align="center"
align="center"
label="字典标签">
</el-table-column>
<el-table-column
prop="dictValue"
header-align="center"
align="center"
label="字典键值">
</el-table-column>
<el-table-column
prop="dictType"
header-align="center"
align="center"
label="字典类型">
</el-table-column>
<el-table-column
prop="cssClass"
header-align="center"
align="center"
label="样式属性(其他样式扩展)">
</el-table-column>
<el-table-column
prop="listClass"
header-align="center"
align="center"
label="表格回显样式">
</el-table-column>
<el-table-column
prop="isDefault"
header-align="center"
align="center"
label="是否默认Y是 N否">
</el-table-column>
<el-table-column
prop="status"
header-align="center"
align="center"
label="状态0正常 1停用">
</el-table-column>
<el-table-column
prop="createBy"
header-align="center"
align="center"
label="创建者">
</el-table-column>
<el-table-column
prop="createTime"
header-align="center"
align="center"
label="创建时间">
</el-table-column>
<el-table-column
prop="updateBy"
header-align="center"
align="center"
label="更新者">
</el-table-column>
<el-table-column
prop="updateTime"
header-align="center"
align="center"
label="更新时间">
</el-table-column>
<el-table-column
prop="remark"
header-align="center"
align="center"
label="备注">
</el-table-column>
<el-table-column
prop="dataCode"
header-align="center"
align="center"
label="字典代码">
</el-table-column>
<el-table-column
fixed="right"
header-align="center"
align="center"
width="150"
label="操作">
<template slot-scope="scope">
<el-button type="text" size="small" @click="addOrUpdateHandle(scope.row.dictCode)">{{ '' }}</el-button>
<el-button v-hasPermi="['autogencode:sysdictdata:delete']" type="text" size="small" @click="deleteHandle(scope.row.dictCode)" style="color: #f56c6c;"></el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="sizeChangeHandle"
@current-change="currentChangeHandle"
:current-page="pageIndex"
:page-sizes="[10, 20, 50, 100]"
:page-size="pageSize"
:total="totalPage"
layout="total, sizes, prev, pager, next, jumper">
</el-pagination>
<!-- 表单弹窗, 新增数据和修改数据 -->
<add-or-update v-if="addOrUpdateVisible" ref="addOrUpdate" @refreshDataList="getDataList"></add-or-update>
</div>
</template>
<script>
import AddOrUpdate from './sysdictdata-add-and-update'
import * as api from '@/api/sysdictdata.js'
export default {
data () {
return {
dataForm: {
dictCode: '',
dictSort: '',
dictLabel: '',
dictValue: '',
dictType: '',
cssClass: '',
listClass: '',
isDefault: '',
status: '',
remark: '',
dataCode: '',
},
//
resetForm() {
this.dataForm = {
dictCode: '',
dictSort: '',
dictLabel: '',
dictValue: '',
dictType: '',
cssClass: '',
listClass: '',
isDefault: '',
status: '',
remark: '',
dataCode: '',
}
},
dataList: [],
pageIndex: 1,
pageSize: 10,
totalPage: 0,
dataListLoading: false,
dataListSelections: [],
addOrUpdateVisible: false
}
},
components: {
AddOrUpdate
},
activated () {
this.getDataList()
},
methods: {
//
getDataList () {
this.dataListLoading = true
// SysDictDataControllerPageParamRequest
const params = {
page: this.pageIndex,
limit: this.pageSize
}
//
if (this.dataForm.dictCode) params.dictCode = this.dataForm.dictCode;
if (this.dataForm.dictSort) params.dictSort = this.dataForm.dictSort;
if (this.dataForm.dictLabel) params.dictLabel = this.dataForm.dictLabel;
if (this.dataForm.dictValue) params.dictValue = this.dataForm.dictValue;
if (this.dataForm.dictType) params.dictType = this.dataForm.dictType;
if (this.dataForm.cssClass) params.cssClass = this.dataForm.cssClass;
if (this.dataForm.listClass) params.listClass = this.dataForm.listClass;
if (this.dataForm.isDefault) params.isDefault = this.dataForm.isDefault;
if (this.dataForm.status) params.status = this.dataForm.status;
if (this.dataForm.remark) params.remark = this.dataForm.remark;
if (this.dataForm.dataCode) params.dataCode = this.dataForm.dataCode;
api.sysdictdataListApi(params).then(res => {
this.dataListLoading = false
this.dataList = res.list || [];
this.totalPage = res.total;
}).catch(e => {
this.dataListLoading = false
})
},
//
sizeChangeHandle (val) {
this.pageSize = val
this.pageIndex = 1
this.getDataList()
},
//
currentChangeHandle (val) {
this.pageIndex = val
this.getDataList()
},
//
selectionChangeHandle (val) {
this.dataListSelections = val
},
// /
addOrUpdateHandle (id) {
this.addOrUpdateVisible = true
this.$nextTick(() => {
this.$refs.addOrUpdate.init(id)
})
},
//
deleteHandle (id) {
let ids = []
let idText = ''
// id
if (id) {
ids = [id]
idText = id
} else {
//
ids = this.dataListSelections.map(item => {
return item.dictCode
})
idText = ids.join(',')
}
this.$confirm(`确定进行删除操作?`, '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// API
api.sysdictdataDeleteApi(ids).then(res => {
this.$message.success('删除成功')
this.getDataList()
})
})
},
}
}
</script>

@ -0,0 +1,98 @@
import Vue from 'vue'
import store from '@/store'
import DataDict from '@/utils/dict'
import { getDicts as getDicts, getBatchDicts } from '@/api/system/dict/data'
function searchDictByKey(dict, key) {
if (key == null && key == "") {
return null
}
try {
for (let i = 0; i < dict.length; i++) {
if (dict[i].key == key) {
return dict[i].value
}
}
} catch (e) {
return null
}
}
function install() {
let waiting = [];
let isRequesting = false;
let timer = null; // 定时器
Vue.use(DataDict, {
metas: {
'*': {
labelField: 'dictLabel',
valueField: 'dictValue',
request(dictMeta) {
const storeDict = searchDictByKey(store.getters.dict, dictMeta.type)
if (storeDict) {
return new Promise(resolve => { resolve(storeDict) })
} else {
return new Promise((resolve, reject) => {
waiting.push({
type: dictMeta.type,
resolve,
reject,
});
if (timer || isRequesting) {
return;
}
const startRequest = () => {
const requesting = [...waiting];
waiting = [];
timer = null;
isRequesting = true;
// 批量获取字典
getBatchDicts(requesting.map(item => item.type)).then(res => {
const datas = res.data || {};
requesting.forEach(item => {
store.dispatch('dict/setDict', { key: item.type, value: datas[item.type] || [] });
item.resolve(datas[item.type] || []);
const wIndex = waiting.findIndex(witem => witem.type == item.type);
if (wIndex > -1) {
waiting[wIndex].resolve(datas[item.type] || []);
waiting.splice(wIndex, 1);
}
});
isRequesting = false;
if (waiting.length > 0) {
startRequest();
}
}).catch(error => {
requesting.forEach(item => {
item.reject(error)
});
isRequesting = false;
if (waiting.length > 0) {
startRequest();
}
});
}
timer = setTimeout(() => {
startRequest();
}, 300);
// getDicts(dictMeta.type).then(res => {
// store.dispatch('dict/setDict', { key: dictMeta.type, value: res.data })
// resolve(res.data)
// }).catch(error => {
// reject(error)
// })
})
}
},
},
},
})
}
export default {
install,
}

@ -0,0 +1,82 @@
<template>
<div v-if="items && items.length > 0 && items[0].raw.listClass && items[0].raw.listClass !== 'default'">
<el-tag v-for="(item, index) in items" :disable-transitions="true" :size="size" :index="index" :key="index"
:type="item.raw.listClass == 'primary' ? '' : item.raw.listClass" :class="item.raw.cssClass" :style="{
'border-color': item.raw.listClass == 'default'? '#DCDFE6' : '',
'color': item.raw.listClass == 'default'? '#606266' : '',
'background-color': item.raw.listClass == 'default'? '#ffffff' : ''
}">
{{ valueShow ? (item.value + ' - ' + item.label) : item.label }}
</el-tag>
</div>
<div v-else>
{{ items.map(item => valueShow ? (item.value + ' - ' + item.label) : item.label).join('、')}}
</div>
</template>
<script>
export default {
name: "DictTag",
props: {
options: {
type: Array,
default: () => [],
},
value: [Number, String, Array],
size: {
type: String,
default: null,
},
valueShow: [Boolean],
},
computed: {
values() {
let myValue = this.value;
if (myValue === null || myValue === undefined || myValue === '') {
return [];
}
if (Array.isArray(myValue)) {
return myValue.filter(item => !!item || item === 0);
}
if (typeof myValue === 'string') {
return myValue.split(',').filter(item => !!item || item === 0);
}
if (typeof myValue === 'number') {
return [myValue];
}
return [];
},
items() {
// const list = this.options.filter(item => {
// return this.values.includes(item.value);
// });
if (!this.values) {
return [];
}
const list = this.values.map(item => {
const findIndex = this.options.findIndex(val => {
return val.value === item;
});
if (findIndex < 0) {
return {
label: item,
value: item,
raw: {
listClass: 'default',
cssClass: '',
cssStyle: '',
},
};
}
return this.options[findIndex];
});
return list;
},
},
};
</script>
<style scoped>
.el-tag+.el-tag {
margin-left: 10px;
}
</style>

@ -11,6 +11,7 @@
const getters = { const getters = {
sidebar: state => state.app.sidebar, sidebar: state => state.app.sidebar,
size: state => state.app.size, size: state => state.app.size,
dict: state => state.dict.dict,
device: state => state.app.device, device: state => state.app.device,
visitedViews: state => state.tagsView.visitedViews, visitedViews: state => state.tagsView.visitedViews,
cachedViews: state => state.tagsView.cachedViews, cachedViews: state => state.tagsView.cachedViews,

@ -0,0 +1,51 @@
const state = {
dict: new Array(),
dictData: {}
}
const mutations = {
SET_DICT: (state, { key, value }) => {
if (key !== null && key !== "") {
state.dict.push({
key: key,
value: value
})
}
},
REMOVE_DICT: (state, key) => {
try {
for (let i = 0; i < state.dict.length; i++) {
if (state.dict[i].key == key) {
state.dict.splice(i, i)
return true
}
}
} catch (e) {
}
},
CLEAN_DICT: (state) => {
state.dict = new Array()
}
}
const actions = {
// 设置字典
setDict({ commit }, data) {
commit('SET_DICT', data)
},
// 删除字典
removeDict({ commit }, key) {
commit('REMOVE_DICT', key)
},
// 清空字典
cleanDict({ commit }) {
commit('CLEAN_DICT')
}
}
export default {
namespaced: true,
state,
mutations,
actions
}

@ -0,0 +1,84 @@
import Vue from 'vue'
import { mergeRecursive } from "@/utils";
import DictMeta from './DictMeta'
import DictData from './DictData'
const DEFAULT_DICT_OPTIONS = {
types: [],
}
/**
* @classdesc 字典
* @property {Object} label 标签对象内部属性名为字典类型名称
* @property {Object} dict 字段数组内部属性名为字典类型名称
* @property {Array.<DictMeta>} _dictMetas 字典元数据数组
*/
export default class Dict {
constructor() {
this.owner = null;
this.label = {};
this.type = {};
}
init(options) {
if (options instanceof Array) {
options = { types: options }
}
const opts = mergeRecursive(DEFAULT_DICT_OPTIONS, options)
if (opts.types === undefined) {
throw new Error('need dict types')
}
const ps = []
this._dictMetas = opts.types.map(t => DictMeta.parse(t))
this._dictMetas.forEach(dictMeta => {
const type = dictMeta.type
Vue.set(this.label, type, {})
Vue.set(this.type, type, [])
if (dictMeta.lazy) {
// console.log(`dict of ${type} will be loaded lazily`);
return
}
ps.push(loadDict(this, dictMeta));
})
return Promise.all(ps)
}
/**
* 重新加载字典
* @param {String} type 字典类型
*/
reloadDict(type) {
const dictMeta = this._dictMetas.find(e => e.type === type)
if (dictMeta === undefined) {
return Promise.reject(`the dict meta of ${type} was not found`)
}
return loadDict(this, dictMeta)
}
}
/**
* 加载字典
* @param {Dict} dict 字典
* @param {DictMeta} dictMeta 字典元数据
* @returns {Promise}
*/
function loadDict(dict, dictMeta) {
return dictMeta.request(dictMeta)
.then(response => {
const type = dictMeta.type
let dicts = dictMeta.responseConverter(response, dictMeta)
// console.log('设置字典', dicts);
if (!(dicts instanceof Array)) {
console.error('the return of responseConverter must be Array.<DictData>')
dicts = []
} else if (dicts.filter(d => d instanceof DictData).length !== dicts.length) {
console.error('the type of elements in dicts must be DictData')
dicts = []
}
dict.type[type].splice(0, Number.MAX_SAFE_INTEGER, ...dicts)
dicts.forEach(d => {
Vue.set(dict.label[type], d.value, d.label)
})
return dicts
})
}

@ -0,0 +1,17 @@
import DictOptions from './DictOptions'
import DictData from './DictData'
// 查找字典key value正确字段
export default function(dict, dictMeta) {
const label = determineDictField(dict, dictMeta.labelField, ...DictOptions.DEFAULT_LABEL_FIELDS)
const value = determineDictField(dict, dictMeta.valueField, ...DictOptions.DEFAULT_VALUE_FIELDS)
return new DictData(dict[label], dict[value], dict)
}
/**
* 确定字典字段
* @param {DictData} dict
* @param {...String} fields
*/
function determineDictField(dict, ...fields) {
return fields.find(f => Object.prototype.hasOwnProperty.call(dict, f))
}

@ -0,0 +1,15 @@
/**
* @classdesc 字典数据
* @property {String} label 标签
* @property {*} value 标签
* @property {Object} raw 原始数据
*/
export default class DictData {
constructor(label, value, raw) {
this.label = label
this.value = value
this.sort = raw?.dictSort
this.code = raw?.dictCode
this.raw = raw; //保存原始数据
}
}

@ -0,0 +1,39 @@
import { mergeRecursive } from "@/utils";
import DictOptions from './DictOptions'
/**
* @classdesc 字典元数据
* @property {String} type 类型
* @property {Function} request 请求
* @property {String} label 标签字段
* @property {String} value 值字段
*/
export default class DictMeta {
constructor(options) {
this.type = options.type
this.request = options.request
this.responseConverter = options.responseConverter
this.labelField = options.labelField
this.valueField = options.valueField
this.lazy = options.lazy === true
}
}
/**
* 解析字典元数据
* @param {Object} options
* @returns {DictMeta}
*/
DictMeta.parse= function(options) {
let opts = null
if (typeof options === 'string') {
opts = DictOptions.metas[options] || {}
opts.type = options
} else if (typeof options === 'object') {
opts = options
}
opts = mergeRecursive(DictOptions.metas['*'], opts);
// console.log('解析结果:', opts)
return new DictMeta(opts)
}

@ -0,0 +1,52 @@
import { mergeRecursive } from "@/utils";
import dictConverter from './DictConverter'
export const options = {
metas: {
'*': {
/**
* 字典请求方法签名为function(dictMeta: DictMeta): Promise
*/
request: (dictMeta) => {
console.log(`load dict ${dictMeta.type}`)
return Promise.resolve([])
},
/**
* 字典响应数据转换器方法签名为function(response: Object, dictMeta: DictMeta): DictData
*/
responseConverter,
// 转化后属性
labelField: 'label',
valueField: 'value',
},
},
/**
* 默认标签字段
*/
DEFAULT_LABEL_FIELDS: ['label', 'name', 'title'],
/**
* 默认值字段
*/
DEFAULT_VALUE_FIELDS: ['value', 'id', 'uid', 'key'],
}
/**
* 映射字典
* @param {Object} response 字典数据
* @param {DictMeta} dictMeta 字典元数据
* @returns {DictData}
*/
function responseConverter(response, dictMeta) {
const dicts = response.content instanceof Array ? response.content : response
if (dicts === undefined) {
console.warn(`no dict data of "${dictMeta.type}" found in the response`)
return []
}
return dicts.map(d => dictConverter(d, dictMeta))
}
export function mergeOptions(src) {
mergeRecursive(options, src)
}
export default options

@ -0,0 +1,33 @@
import Dict from './Dict'
import { mergeOptions } from './DictOptions'
export default function(Vue, options) {
mergeOptions(options)
Vue.mixin({
data() {
if (this.$options === undefined || this.$options.dicts === undefined || this.$options.dicts === null) {
return {}
}
const dict = new Dict()
dict.owner = this
return {
dict
}
},
created() {
if (!(this.dict instanceof Dict)) {
return
}
options.onCreated && options.onCreated(this.dict)
this.dict.init(this.$options.dicts).then(() => {
options.onReady && options.onReady(this.dict)
this.$nextTick(() => {
this.$emit('dictReady', this.dict)
if (this.$options.methods && this.$options.methods.onDictReady instanceof Function) {
this.$options.methods.onDictReady.call(this, this.dict)
}
})
})
},
})
}

@ -431,3 +431,18 @@ export function isWriteOff() {
} }
} }
// 数据合并
export function mergeRecursive(source, target) {
for (var p in target) {
try {
if (target[p].constructor == Object) {
source[p] = mergeRecursive(source[p], target[p]);
} else {
source[p] = target[p];
}
} catch (e) {
source[p] = target[p];
}
}
return source;
};

@ -169,52 +169,36 @@ export function handleTree(data, id, parentId, children) {
* 路由数据遍历 * 路由数据遍历
* *
*/ */
export function formatRoutes(routerArr){ export function formatRoutes(routerArr) {
let arr = [],obj = {}; /**
routerArr.forEach(tmp => { * 递归处理单个路由项
obj = { * @param {Object} routeItem 路由项
id:tmp.id, * @param {String} parentPath 父级路径用于构建完整路径
pid:tmp.pid, * @returns {Object} 格式化后的路由对象
name:tmp.name, */
url:tmp.component, function formatRouteItem(routeItem, parentPath = '') {
path:'/' + tmp.pid + '/', const currentPath = parentPath ? `${parentPath}${routeItem.pid}/` : `/${routeItem.pid}/`;
perms:tmp.perms,
child:tmp.childList.length ? tmp.childList.map(item=>{ const formattedRoute = {
return { id: routeItem.id,
id:item.id, pid: routeItem.pid,
pid:item.pid, name: routeItem.name,
name:item.name, url: routeItem.component,
url:item.component, path: currentPath,
path:'/' + tmp.pid + '/' + item.pid + '/', perms: routeItem.perms,
perms:item.perms, child: [],
extra:item.icon, extra: routeItem.icon
child:item.childList.length ? item.childList.map(item1=>{ };
return {
id:item1.id, // 递归处理子路由
pid:item1.pid, if (routeItem.childList && routeItem.childList.length > 0) {
name:item1.name, formattedRoute.child = routeItem.childList.map(child =>
url:item1.component, formatRouteItem(child, currentPath)
path:'/' + tmp.pid + '/' + item.pid + '/' + item1.pid + '/', );
perms:item1.perms,
extra:item1.icon,
child:item1.childList.length ? item1.childList.map(item2=>{
return {
id:item2.id,
pid:item2.pid,
name:item2.name,
url:item2.component,
path:'/' + tmp.pid + '/' + item.pid + '/' + item1.pid + '/' + item2.pid + '/',
perms:item2.perms,
extra:item2.icon,
}
}) : []
}
}) : []
}
}) : [],
extra:tmp.icon,
} }
arr.push(obj);
}) return formattedRoute;
return arr; }
}
return routerArr.map(item => formatRouteItem(item));
}
Loading…
Cancel
Save