feat: 配置管理基础完成

This commit is contained in:
H0nGzA1
2023-03-14 21:15:43 +08:00
parent e4b4e6aa0b
commit 3f91f973b9
9 changed files with 983 additions and 0 deletions

View File

@@ -0,0 +1,53 @@
import { request } from '/@/utils/service';
import { PageQuery, AddReq, DelReq, EditReq, InfoReq } from '@fast-crud/fast-crud';
import XEUtils from 'xe-utils';
export const apiPrefix = '/api/system/system_config/';
export function GetList(query: PageQuery) {
return request({
url: apiPrefix,
method: 'get',
params: query,
});
}
export function GetObj(id: InfoReq) {
return request({
url: apiPrefix + id,
method: 'get',
});
}
export function AddObj(obj: AddReq) {
return request({
url: apiPrefix,
method: 'post',
data: obj,
});
}
export function UpdateObj(obj: EditReq) {
return request({
url: apiPrefix + obj.id + '/',
method: 'put',
data: obj,
});
}
export function DelObj(id: DelReq) {
return request({
url: apiPrefix + id + '/',
method: 'delete',
data: { id },
});
}
/*
获取所有的model及字段信息
*/
export function GetAssociationTable() {
return request({
url: apiPrefix + 'get_association_table/',
method: 'get',
params: {},
});
}

View File

@@ -0,0 +1,156 @@
<template>
<div style="padding: 20px">
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="所属分组" prop="parent">
<el-select v-model="form.parent" placeholder="请选择分组" clearable>
<el-option :label="item.title" :value="item.id" :key="index" v-for="(item, index) in parentOptions"></el-option>
</el-select>
</el-form-item>
<el-form-item label="标题" prop="title">
<el-input v-model="form.title" placeholder="请输入" clearable></el-input>
</el-form-item>
<el-form-item label="key值" prop="key">
<el-input v-model="form.key" placeholder="请输入" clearable></el-input>
</el-form-item>
<el-form-item label="表单类型" prop="form_item_type">
<el-select v-model="form.form_item_type" placeholder="请选择" clearable>
<el-option :label="item.label" :value="item.value" :key="index" v-for="(item, index) in dictionary('config_form_type')"></el-option>
</el-select>
</el-form-item>
<el-form-item
v-if="[4, 5, 6].indexOf(form.form_item_type) > -1"
label="字典key"
prop="setting"
:rules="[{ required: true, message: '不能为空' }]"
>
<el-input v-model="form.setting" placeholder="请输入dictionary中key值" clearable></el-input>
</el-form-item>
<div v-if="[13, 14].indexOf(form.form_item_type) > -1">
<associationTable ref="associationTableRef" v-model="form.setting" @updateVal="associationTableUpdate"></associationTable>
</div>
<el-form-item label="校验规则">
<el-select v-model="form.rule" multiple placeholder="请选择(可多选)" clearable>
<el-option :label="item.label" :value="item.value" :key="index" v-for="(item, index) in ruleOptions"></el-option>
</el-select>
</el-form-item>
<el-form-item label="提示信息" prop="placeholder">
<el-input v-model="form.placeholder" placeholder="请输入" clearable></el-input>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model="form.sort" :min="0" :max="99"></el-input-number>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">立即创建</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup lang="ts">
import * as api from '../api';
import associationTable from './components/associationTable.vue';
import { ref, reactive, onMounted } from 'vue';
import type { FormInstance, FormRules } from 'element-plus';
import { successMessage } from '/@/utils/message';
import { dictionary } from '/@/utils/dictionary';
let form: any = reactive({
parent: null,
title: null,
key: null,
form_item_type: '',
rule: null,
placeholder: null,
});
const formRef = ref<FormInstance>();
const associationTableRef: any = ref<FormInstance>();
const rules = reactive<FormRules>({
parent: [
{
required: true,
message: '请选择',
},
],
title: [
{
required: true,
message: '请输入',
},
],
key: [
{
required: true,
message: '请输入',
},
{
pattern: /^[A-Za-z0-9_]+$/,
message: '请输入数字、字母或下划线',
},
],
form_item_type: [
{
required: true,
message: '请输入',
},
],
});
let parentOptions: any = ref([]);
let ruleOptions = ref([
{
label: '必填项',
value: '{"required": true, "message": "必填项不能为空"}',
},
{
label: '邮箱',
value: '{ "type": "email", "message": "请输入正确的邮箱地址"}',
},
{
label: 'URL地址',
value: '{ "type": "url", "message": "请输入正确的URL地址"}',
},
]);
const getParent = () => {
api
.GetList({
parent__isnull: true,
limit: 999,
})
.then((res: any) => {
parentOptions.value = res.data;
});
};
const onSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid, fields) => {
if (valid) {
api.AddObj(form).then((res: any) => {
if (res.code == 2000) successMessage('新增成功');
});
} else {
console.log('error submit!', fields);
}
});
};
// 关联表数据更新
const associationTableUpdate = () => {
return new Promise(function (resolve, reject) {
if (associationTableRef) {
if (!associationTableRef.onSubmit()) {
// eslint-disable-next-line prefer-promise-reject-errors
return reject(false);
}
const { formObj } = associationTableRef;
form.setting = formObj;
return resolve(true);
} else {
return resolve(true);
}
});
};
onMounted(() => {
getParent();
});
</script>
<style></style>

View File

@@ -0,0 +1,60 @@
<template>
<div style="padding: 20px">
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="标题" prop="title">
<el-input v-model="form.title"></el-input>
</el-form-item>
<el-form-item label="key值" prop="key">
<el-input v-model="form.key"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit(formRef)">立即创建</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup lang="ts">
import * as api from '../api';
import { ref, reactive } from 'vue';
import type { FormInstance, FormRules } from 'element-plus';
import { successMessage } from '/@/utils/message';
let form = reactive({
title: null,
key: null,
});
const formRef = ref<FormInstance>();
const rules = reactive<FormRules>({
title: [
{
required: true,
message: '请输入',
},
],
key: [
{
required: true,
message: '请输入',
},
{
pattern: /^[A-Za-z0-9]+$/,
message: '只能是英文和数字',
},
],
});
const onSubmit = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
await formEl.validate((valid, fields) => {
if (valid) {
api.AddObj(form).then((res: any) => {
if (res.code == 2000) successMessage('新增成功');
});
} else {
console.log('error submit!', fields);
}
});
};
</script>
<style></style>

View File

@@ -0,0 +1,104 @@
<template>
<div>
<el-form :model="formObj" ref="associationRef">
<el-form-item label="关联表" prop="table" :rules="[{ required: true, message: '必填项', trigger: 'blur' }]">
<el-select v-model="formObj.table" filterable clearable placeholder="请选择" @change="handleChange">
<el-option v-for="item in tableOptions" :key="item.table" :label="item.tableName" :value="item.table">
<span style="float: left">{{ item.tableName }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.table }}</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="显示字段" prop="field" :rules="[{ required: true, message: '必填项', trigger: 'blur' }]">
<el-select v-model="formObj.field" filterable clearable placeholder="请选择">
<el-option v-for="item in labelOptions" :key="item.table" :label="item.title" :value="item.field">
<span style="float: left">{{ item.field }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.title }}</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="储存字段" prop="primarykey" :rules="[{ required: true, message: '必填项', trigger: 'blur' }]">
<el-select v-model="formObj.primarykey" filterable clearable placeholder="请选择">
<el-option v-for="(item, index) in labelOptions" :key="index" :label="item.title" :value="item.field">
<span style="float: left">{{ item.field }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.title }}</span>
</el-option>
</el-select>
</el-form-item>
<el-form-item label="过滤条件" prop="oldSearchField" :rules="[{ required: true, message: '必填项', trigger: 'blur' }]">
<el-select v-model="formObj.oldSearchField" multiple filterable clearable placeholder="请选择" @change="handleSearch">
<el-option v-for="(item, index) in labelOptions" :key="index" :label="item.title" :value="item.field">
<span style="float: left">{{ item.field }}</span>
<span style="float: right; color: #8492a6; font-size: 13px">{{ item.title }}</span>
</el-option>
</el-select>
</el-form-item>
</el-form>
</div>
</template>
<script setup lang="ts">
import * as api from '../../api';
import { ref, reactive, onMounted } from 'vue';
import type { FormInstance, FormRules } from 'element-plus';
import { successMessage } from '/@/utils/message';
let formObj: any = reactive({
table: null,
primarykey: null,
field: null,
searchField: null,
oldSearchField: null,
});
let searchField = ref('');
let tableOptions: any = ref([]);
let labelOptions: any = ref([]);
const associationRef: any = ref<FormInstance>();
const emits = defineEmits(['updateVal']);
const props = defineProps(['value']);
// 初始化数据
const init = () => {
api.GetAssociationTable().then((res: any) => {
const { data } = res.data;
tableOptions = data;
// 设置默认选中
formObj.table = data[0].table;
labelOptions = data[0].tableFields;
formObj.primarykey = 'id';
formObj.field = 'id';
});
};
// 选中事件
const handleChange = (val: any) => {
const { tableFields } = tableOptions.find((item: any) => {
return item.table === val;
});
labelOptions = tableFields;
};
// 过滤条件选中
const handleSearch = (val: any) => {
const fields = labelOptions.filter((item: any) => {
return val.indexOf(item.field) > -1;
});
formObj.searchField = fields;
};
// 更新数据
const handleUpdate = () => {
emits('updateVal', formObj);
};
// 数据验证
const onSubmit = () => {
let res = false;
associationRef.value.validate((valid: any) => {
if (valid) {
res = true;
} else {
return false;
}
});
return res;
};
</script>
<style></style>

View File

@@ -0,0 +1,505 @@
<template>
<div>
<el-row :gutter="10">
<el-col :span="4">变量标题</el-col>
<el-col :span="10">变量值</el-col>
<el-col :span="4">变量名</el-col>
<el-col :span="2">是否前端配置</el-col>
<el-col :span="3" :offset="1">操作</el-col>
</el-row>
<el-form ref="formRef" :model="form" label-width="240px" label-position="left" style="margin-top: 20px">
<el-form-item
:label="item.title"
:prop="['array'].indexOf(item.form_item_type_label) > -1 ? '' : item.key"
:key="index"
:rules="item.rule || []"
v-for="(item, index) in formList"
>
<template slot="label">
<el-input v-if="item.edit" v-model="item.title" style="display: inline-block; width: 200px" placeholder="请输入标题"></el-input>
<span v-else>{{ item.title }}</span>
</template>
<el-col :span="11">
<!-- 文本 -->
<el-input
:key="index"
v-if="['text', 'textarea'].indexOf(item.form_item_type_label) > -1"
:type="item.form_item_type_label"
v-model="form[item.key]"
:placeholder="item.placeholder"
clearable
></el-input>
<el-input-number :key="index + 1" v-else-if="item.form_item_type_label === 'number'" v-model="form[item.key]" :min="0"></el-input-number>
<!-- datetimedatetime -->
<el-date-picker
v-else-if="['datetime', 'date', 'time'].indexOf(item.form_item_type_label) > -1"
v-model="form[item.key]"
:key="index + 2"
:type="item.form_item_type_label"
:placeholder="item.placeholder"
>
</el-date-picker>
<!-- select -->
<el-select
:key="index + 3"
v-else-if="item.form_item_type_label === 'select'"
v-model="form[item.key]"
:placeholder="item.placeholder"
clearable
>
<el-option v-for="item in dictionary(item.setting) || []" :key="item.value" :label="item.label" :value="item.value"> </el-option>
</el-select>
<!-- checkbox -->
<el-checkbox-group
:key="index + 4"
v-else-if="item.form_item_type_label === 'checkbox'"
v-model="form[item.key]"
:placeholder="item.placeholder"
>
<el-checkbox v-for="item in dictionary(item.setting) || []" :key="item.value" :label="item.value" :value="item.value">
{{ item.label }}
</el-checkbox>
</el-checkbox-group>
<!-- radio -->
<el-radio-group
:key="index + 5"
v-else-if="item.form_item_type_label === 'radio'"
v-model="form[item.key]"
:placeholder="item.placeholder"
clearable
>
<el-radio v-for="item in dictionary(item.setting) || []" :key="item.value" :label="item.value" :value="item.value">
{{ item.label }}
</el-radio>
</el-radio-group>
<!-- switch -->
<el-switch
:key="index + 6"
v-else-if="item.form_item_type_label === 'switch'"
v-model="form[item.key]"
active-color="#13ce66"
inactive-color="#ff4949"
>
</el-switch>
<!-- 图片 -->
<div v-else-if="['img', 'imgs'].indexOf(item.form_item_type_label) > -1" :key="index + 7">
<el-upload
:action="uploadUrl"
:headers="uploadHeaders"
name="file"
:accept="'image/*'"
:on-preview="handlePictureCardPreview"
:on-success="
(response:any, file:any, fileList:any) => {
handleUploadSuccess(response, file, fileList, item.key);
}
"
:on-error="handleError"
:on-exceed="handleExceed"
:before-remove="
(file:any, fileList:any) => {
beforeRemove(file, fileList, item.key);
}
"
:multiple="item.form_item_type_label !== 'img'"
:limit="item.form_item_type_label === 'img' ? 1 : 5"
:ref="'imgUpload_' + item.key"
:data-keyname="item.key"
:file-list="item.value ? item.value : []"
list-type="picture-card"
>
<i class="el-icon-plus"></i>
<div slot="tip" class="el-upload__tip">选取图片后,需手动上传到服务器,并且只能上传jpg/png文件</div>
</el-upload>
<el-dialog :visible.sync="dialogImgVisible">
<img width="100%" :src="dialogImageUrl" alt="" />
</el-dialog>
</div>
<!-- 文件 -->
<div v-else-if="['file'].indexOf(item.form_item_type_label) > -1" :key="index + 8">
<el-upload
:action="uploadUrl"
:headers="uploadHeaders"
name="file"
:on-preview="handlePictureCardPreview"
:on-success="
(response:any, file:any, fileList:any) => {
handleUploadSuccess(response, file, fileList, item.key);
}
"
:on-error="handleError"
:on-exceed="handleExceed"
:before-remove="
(file:any, fileList:any) => {
beforeRemove(file, fileList, item.key);
}
"
:limit="5"
:ref="'fileUpload_' + item.key"
:data-keyname="item.key"
:file-list="item.value"
list-type="picture-card"
>
<i class="el-icon-plus"></i>
<div slot="tip" class="el-upload__tip">选取图片后,需手动上传到服务器,并且只能上传jpg/png文件</div>
</el-upload>
<el-dialog :visible.sync="dialogImgVisible">
<img width="100%" :src="dialogImageUrl" alt="" />
</el-dialog>
</div>
<!-- 关联表 -->
<div v-else-if="['foreignkey', 'manytomany'].indexOf(item.form_item_type_label) > -1" :key="index + 9">
<table-selector
v-model="form[item.key]"
:el-props="{
pagination: true,
columns: item.setting.searchField,
}"
:dict="{
url: '/api/system/system_config/get_table_data/' + item.id + '/',
value: item.setting.primarykey,
label: item.setting.field,
}"
:pagination="true"
:multiple="item.form_item_type_label === 'manytomany'"
></table-selector>
</div>
<!-- 数组 -->
<div v-else-if="item.form_item_type_label === 'array'" :key="index + 10">
<vxe-table
border
resizable
auto-resize
show-overflow
keep-source
:ref="'xTable_' + item.key"
height="200"
:edit-rules="validRules"
:edit-config="{ trigger: 'click', mode: 'row', showStatus: true }"
>
<vxe-column field="title" title="标题" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.title" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="key" title="键名" :edit-render="{ autofocus: '.vxe-input--inner' }">
<template #edit="{ row }">
<vxe-input v-model="row.key" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column field="value" title="键值" :edit-render="{}">
<template #edit="{ row }">
<vxe-input v-model="row.value" type="text"></vxe-input>
</template>
</vxe-column>
<vxe-column title="操作" width="100" show-overflow>
<template #default="{ row, index }">
<el-popover placement="top" width="160" v-model="childRemoveVisible">
<p>删除后无法恢复,确定删除吗?</p>
<div style="text-align: right; margin: 0">
<el-button size="mini" type="text" @click="childRemoveVisible = false">取消</el-button>
<el-button type="primary" size="mini" @click="onRemoveChild(row, index, item.key)">确定</el-button>
</div>
<el-button type="text" slot="reference">删除</el-button>
</el-popover>
</template>
</vxe-column>
</vxe-table>
<div>
<el-button size="mini" @click="onAppend('xTable_' + item.key)">追加</el-button>
</div>
</div>
</el-col>
<el-col :span="4" :offset="1">
<el-input v-if="item.edit" v-model="item.new_key" style="width: 200px" placeholder="请输入变量key">
<template slot="prepend">
<span style="padding: 0px 5px">{{ editableTabsItem.key }}</span>
</template>
</el-input>
<span v-else>{{ editableTabsItem.key }}.{{ item.key }}</span>
</el-col>
<el-col :span="3" :offset="1">
<el-switch v-model="item.status" active-color="#13ce66" inactive-color="#ff4949"> </el-switch>
</el-col>
<el-col :span="2">
<el-button v-if="item.edit" size="mini" type="primary" icon="el-icon-success" @click="onEditSave(item)"></el-button>
<el-button v-else size="mini" type="primary" icon="el-icon-edit" @click="onEdit(index)"></el-button>
<el-popconfirm title="确定删除该条数据吗" @confirm="onDelRow(item)">
<el-button size="mini" type="danger" icon="el-icon-delete" slot="reference"></el-button>
</el-popconfirm>
</el-col>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">确定</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script setup lang="ts">
import * as api from '../api';
import { dictionary } from '/@/utils/dictionary';
import { getBaseURL } from '/@/utils/baseUrl';
import { ref, reactive, watch, nextTick } from 'vue';
import type { FormInstance, FormRules, TableInstance } from 'element-plus';
import { successMessage, errorMessage } from '/@/utils/message';
import { Session } from '/@/utils/storage';
const props = defineProps(['options', 'editableTabsItem']);
let form: any = reactive({});
let formList: any = ref([]);
let childTableData = ref([]);
let childRemoveVisible = ref(false);
const validRules = reactive<FormRules>({
title: [
{
required: true,
message: '必须填写',
},
],
key: [
{
required: true,
message: '必须填写',
},
],
value: [
{
required: true,
message: '必须填写',
},
],
});
const formRef = ref<FormInstance>();
let uploadUrl = ref(getBaseURL + 'api/system/file/');
let uploadHeaders = ref({
Authorization: 'JWT ' + Session.get('token'),
});
let dialogImageUrl = ref('');
let dialogImgVisible = ref(false);
let uploadImgKey = ref(null);
// 获取数据
const getInit = () => {
api.GetList({ parent: props.options.id, limit: 999 }).then((res: any) => {
let data = res.data;
formList = data;
const formData: any = {};
for (const item of data) {
const key = item.key;
if (item.value) {
formData[key] = item.value;
} else {
if ([5, 12, 14].indexOf(item.form_item_type) !== -1) {
formData[key] = [];
} else {
formData[key] = undefined;
}
}
if (item.form_item_type_label === 'array') {
console.log('test');
nextTick(() => {
const tableName = 'xTable_' + key;
const tabelRef = ref<TableInstance>();
console.log(tabelRef);
// const $table = this.$refs[tableName][0];
// $table.loadData(item.chinldern);
});
}
}
form = JSON.parse(JSON.stringify(formData));
});
};
// 提交数据
const onSubmit = () => {
// const form = JSON.parse(JSON.stringify(form));
const keys = Object.keys(form);
const values = Object.values(form);
for (const index in formList) {
const item = formList[index];
// eslint-disable-next-line camelcase
const form_item_type_label = item.form_item_type_label;
// eslint-disable-next-line camelcase
if (form_item_type_label === 'array') {
const parentId = item.id;
const tableName = 'xTable_' + item.key;
// const $table = this.$refs[tableName][0];
// const { tableData } = $table.getTableData();
// for (const child of tableData) {
// if (!child.id && child.key && child.value) {
// child.parent = parentId;
// child.id = null;
// formList.push(child);
// }
// }
// // 必填项的判断
// for (const arr of item.rule) {
// if (arr.required && tableData.length === 0) {
// errorMessage(item.title + '不能为空');
// return;
// }
// }
// item.value = tableData;
}
// 赋值操作
keys.map((mapKey, mapIndex) => {
if (mapKey === item.key) {
if (item.form_item_type_label !== 'array') {
item.value = values[mapIndex];
}
// 必填项的验证
if (['img', 'imgs'].indexOf(item.form_item_type_label) > -1) {
for (const arr of item.rule) {
if (arr.required && item.value === null) {
errorMessage(item.title + '不能为空');
return;
}
}
}
}
});
}
// formRef.clearValidate();
// formRef.validate((valid) => {
// if (valid) {
// api.saveContent(this.options.id, this.formList).then((res) => {
// this.$message.success('保存成功');
// this.refreshView();
// });
// } else {
// console.log('error submit!!');
// return false;
// }
// });
};
// 追加
const onAppend = (tableName: any) => {
// const $table = this.$refs[tableName][0];
// const { tableData } = $table.getTableData();
// const tableLength = tableData.length;
// if (tableLength === 0) {
// const { row: newRow } = $table.insert();
// console.log(newRow);
// } else {
// const errMap = $table.validate().catch((errMap: any) => errMap);
// if (errMap) {
// errorMessage('校验不通过!');
// } else {
// const { row: newRow } = $table.insert();
// console.log(newRow);
// }
// }
};
// 子表删除
const onRemoveChild = (row: any, index: any, refName: any) => {
console.log(row, index);
if (row.id) {
api.DelObj(row.id).then((res: any) => {
// this.refreshView();
});
} else {
// this.childTableData.splice(index, 1);
// const tableName = 'xTable_' + refName;
// const tableData = this.$refs[tableName][0].remove(row);
// console.log(tableData);
}
};
// 图片预览
const handlePictureCardPreview = (file: any) => {
dialogImageUrl = file.url;
dialogImgVisible.value = true;
};
// 判断是否为图片
// 封装一个判断图片文件后缀名的方法
const isImage = (fileName: any) => {
if (typeof fileName !== 'string') return;
const name = fileName.toLowerCase();
return name.endsWith('.png') || name.endsWith('.jpeg') || name.endsWith('.jpg') || name.endsWith('.png') || name.endsWith('.bmp');
};
// 上传成功
const handleUploadSuccess = (response: any, file: any, fileList: any, imgKey: any) => {
const that = this;
const { code, msg } = response;
if (code === 2000) {
const { url } = response.data;
const { name } = file;
const type = isImage(name);
if (!type) {
errorMessage('只允许上传图片');
} else {
const uploadImgKey = form[imgKey];
if (!uploadImgKey || uploadImgKey === '') {
form[imgKey] = [];
}
// console.log(len)
const dict = {
name: name,
url: getBaseURL() + url,
};
form[imgKey].push(dict);
}
} else {
errorMessage('上传失败,' + JSON.stringify(msg));
}
};
// 上传失败
const handleError = () => {
errorMessage('上传失败');
};
// 上传超出限制
const handleExceed = () => {
errorMessage('超过文件上传数量');
};
// 删除时的钩子
const beforeRemove = (file: any, fileList: any, key: any) => {
var index = 0;
form[key].map((value: any, inx: any) => {
if (value.uid === file.uid) index = inx;
});
form[key].splice(index, 1);
};
// 配置的行删除
const onDelRow = (obj: any) => {
api.DelObj(obj.id).then((res: any) => {
// this.refreshView();
});
};
// 行编辑
const onEdit = (index: any) => {
// that.$set(that.formList[index], 'new_key', that.formList[index].key)
// that.$set(that.formList[index], 'edit', true)
};
// 行编辑保存
const onEditSave = (obj: any) => {
obj.key = JSON.parse(JSON.stringify(obj.new_key));
api.UpdateObj(obj).then((res: any) => {
// this.refreshView();
});
};
watch(
props.options,
(nv) => {
if (nv && nv.id) {
getInit();
}
},
{ immediate: true }
);
</script>
<style></style>

View File

@@ -0,0 +1,82 @@
<template>
<el-card>
<div>
<el-header>
<div class="yxt-flex-between">
<div>
<el-tag>系统配置:您可以对您的网站进行自定义配置</el-tag>
</div>
<div>
<el-button-group>
<el-button type="primary" size="small" :icon="FolderAdd" @click="tabsDrawer = true"> 添加分组 </el-button>
<el-button size="small" type="warning" :icon="Edit" @click="contentDrawer = true"> 添加内容 </el-button>
</el-button-group>
</div>
</div>
</el-header>
</div>
<div>
<el-drawer v-if="tabsDrawer" title="添加分组" v-model="tabsDrawer" direction="rtl" size="30%">
<addTabs></addTabs>
</el-drawer>
</div>
<div>
<el-drawer v-if="contentDrawer" title="添加内容" v-model="contentDrawer" direction="rtl" size="30%">
<addContent></addContent>
</el-drawer>
</div>
<el-tabs type="border-card" v-model="editableTabsValue">
<el-tab-pane :key="index" v-for="(item, index) in editableTabs" :label="item.title" :name="item.key">
<span slot="label" v-if="item.icon"><i :class="item.icon" style="font-weight: 1000; font-size: 16px"></i></span>
<el-row v-if="item.icon">
<el-col :offset="4" :span="8">
<addContent></addContent>
</el-col>
</el-row>
<formContent v-else :options="item" :editableTabsItem="item"></formContent>
</el-tab-pane>
</el-tabs>
</el-card>
</template>
<script lang="ts" setup>
import { Edit, FolderAdd } from '@element-plus/icons-vue';
import * as api from './api';
import addTabs from './components/addTabs.vue';
import addContent from './components/addContent.vue';
import formContent from './components/formContent.vue';
import { ref, onMounted } from 'vue';
let tabsDrawer = ref(false);
let contentDrawer = ref(false);
let editableTabsValue = ref('base');
let editableTabs: any = ref([]);
const getTabs = () => {
api
.GetList({
limit: 999,
parent__isnull: true,
})
.then((res: any) => {
let data = res.data;
data.push({
title: '无',
icon: 'el-icon-plus',
key: 'null',
});
editableTabs.value = data;
});
};
onMounted(() => {
getTabs();
});
</script>
<style>
/*用 flex 两边对齐*/
.yxt-flex-between {
display: flex;
justify-content: space-between;
}
</style>