mirror of
https://github.com/bufanyun/hotgo.git
synced 2025-12-30 12:05:57 +08:00
发布代码生成、更新20+表单组件,优化数据字典,gf版本更新到2.3.1
This commit is contained in:
@@ -15,7 +15,7 @@
|
||||
>
|
||||
<n-descriptions bordered label-placement="left" class="py-2">
|
||||
<n-descriptions-item label="版本">
|
||||
<n-tag type="info"> 2.0.3 </n-tag>
|
||||
<n-tag type="info"> {{ config?.version }}</n-tag>
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="最后编译时间">
|
||||
<n-tag type="info"> {{ lastBuildTime }} </n-tag>
|
||||
@@ -29,9 +29,7 @@
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="预览地址">
|
||||
<div class="flex items-center">
|
||||
<a href="https://hotgo.facms.cn/admin" class="py-2" target="_blank"
|
||||
>查看预览地址</a
|
||||
>
|
||||
<a href="https://hotgo.facms.cn/admin" class="py-2" target="_blank">查看预览地址</a>
|
||||
</div>
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="Github">
|
||||
@@ -82,6 +80,11 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref } from 'vue';
|
||||
import { useUserStoreWidthOut } from '@/store/modules/user';
|
||||
|
||||
const useUserStore = useUserStoreWidthOut();
|
||||
const config = ref(useUserStore.config);
|
||||
export interface schemaItem {
|
||||
field: string;
|
||||
label: string;
|
||||
|
||||
@@ -1,5 +1,55 @@
|
||||
import { h } from 'vue';
|
||||
import { NAvatar, NTag } from 'naive-ui';
|
||||
import { h, ref } from 'vue';
|
||||
import { NAvatar, NImage, NTag } from 'naive-ui';
|
||||
import { getFileExt } from '@/utils/urlUtils';
|
||||
import { Dicts } from '@/api/dict/dict';
|
||||
import { getOptionLabel, getOptionTag, Options } from '@/utils/hotgo';
|
||||
import { FormSchema } from '@/components/Form';
|
||||
import { isNullOrUnDef } from '@/utils/is';
|
||||
export const options = ref<Options>({
|
||||
sys_normal_disable: [],
|
||||
config_upload_drive: [],
|
||||
});
|
||||
|
||||
export const schemas = ref<FormSchema[]>([
|
||||
{
|
||||
field: 'member_id',
|
||||
component: 'NInput',
|
||||
label: '用户ID',
|
||||
componentProps: {
|
||||
placeholder: '请输入用户ID',
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
rules: [{ message: '请输入用户ID', trigger: ['blur'] }],
|
||||
},
|
||||
{
|
||||
field: 'drive',
|
||||
component: 'NSelect',
|
||||
label: '选择驱动',
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
placeholder: '请选择驱动',
|
||||
options: [],
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
component: 'NSelect',
|
||||
label: '状态',
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
placeholder: '请选择类型',
|
||||
options: [],
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
@@ -11,7 +61,7 @@ export const columns = [
|
||||
key: 'appId',
|
||||
},
|
||||
{
|
||||
title: '会员ID',
|
||||
title: '用户ID',
|
||||
key: 'memberId',
|
||||
},
|
||||
{
|
||||
@@ -45,16 +95,40 @@ export const columns = [
|
||||
key: 'fileUrl',
|
||||
width: 80,
|
||||
render(row) {
|
||||
return h(NAvatar, {
|
||||
size: 40,
|
||||
if (row.fileUrl === '') {
|
||||
return ``;
|
||||
}
|
||||
if (row.kind !== 'images') {
|
||||
return h(
|
||||
NAvatar,
|
||||
{
|
||||
width: '40px',
|
||||
height: '40px',
|
||||
'max-width': '100%',
|
||||
'max-height': '100%',
|
||||
},
|
||||
{
|
||||
default: () => getFileExt(row.fileUrl),
|
||||
}
|
||||
);
|
||||
}
|
||||
return h(NImage, {
|
||||
width: 40,
|
||||
height: 40,
|
||||
src: row.fileUrl,
|
||||
style: {
|
||||
width: '40px',
|
||||
height: '40px',
|
||||
'max-width': '100%',
|
||||
'max-height': '100%',
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '本地路径',
|
||||
key: 'path',
|
||||
},
|
||||
// {
|
||||
// title: '本地路径',
|
||||
// key: 'path',
|
||||
// },
|
||||
{
|
||||
title: '扩展名',
|
||||
key: 'ext',
|
||||
@@ -67,24 +141,44 @@ export const columns = [
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
render(row) {
|
||||
if (isNullOrUnDef(row.status)) {
|
||||
return ``;
|
||||
}
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
type: row.status == 1 ? 'success' : 'warning',
|
||||
type: getOptionTag(options.value.sys_normal_disable, row.status),
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => (row.status == 1 ? '正常' : '隐藏'),
|
||||
default: () => getOptionLabel(options.value.sys_normal_disable, row.status),
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
title: '上传时间',
|
||||
key: 'createdAt',
|
||||
},
|
||||
];
|
||||
|
||||
async function loadOptions() {
|
||||
options.value = await Dicts({
|
||||
types: ['sys_normal_disable', 'config_upload_drive'],
|
||||
});
|
||||
for (const item of schemas.value) {
|
||||
switch (item.field) {
|
||||
case 'status':
|
||||
item.componentProps.options = options.value.sys_normal_disable;
|
||||
break;
|
||||
case 'drive':
|
||||
item.componentProps.options = options.value.config_upload_drive;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await loadOptions();
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:openChecked="true"
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
@@ -29,7 +30,16 @@
|
||||
<UploadOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
上传附件
|
||||
上传图片
|
||||
</n-button>
|
||||
|
||||
<n-button type="primary" @click="addFileTable">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<UploadOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
上传文件
|
||||
</n-button>
|
||||
|
||||
<n-button type="error" @click="batchDelete" :disabled="batchDeleteDisabled">
|
||||
@@ -48,12 +58,12 @@
|
||||
:show-icon="false"
|
||||
preset="dialog"
|
||||
style="width: 60%"
|
||||
title="上传附件"
|
||||
title="上传图片"
|
||||
>
|
||||
<n-upload
|
||||
multiple
|
||||
directory-dnd
|
||||
:action="`${uploadUrl}/admin/upload/image`"
|
||||
:action="`${uploadUrl}${urlPrefix}/upload/image`"
|
||||
:headers="uploadHeaders"
|
||||
:data="{ type: 0 }"
|
||||
@before-upload="beforeUpload"
|
||||
@@ -66,7 +76,39 @@
|
||||
<n-upload-dragger>
|
||||
<div style="margin-bottom: 12px">
|
||||
<n-icon size="48" :depth="3">
|
||||
<archive-icon />
|
||||
<CloudUploadOutlined />
|
||||
</n-icon>
|
||||
</div>
|
||||
<n-text style="font-size: 16px"> 点击或者拖动图片到该区域来上传</n-text>
|
||||
<n-p depth="3" style="margin: 8px 0 0 0"> 单次最多允许20个图片</n-p>
|
||||
</n-upload-dragger>
|
||||
</n-upload>
|
||||
</n-modal>
|
||||
|
||||
<n-modal
|
||||
v-model:show="showFileModal"
|
||||
:show-icon="false"
|
||||
preset="dialog"
|
||||
style="width: 60%"
|
||||
title="上传文件"
|
||||
>
|
||||
<n-upload
|
||||
multiple
|
||||
directory-dnd
|
||||
:action="`${uploadUrl}${urlPrefix}/upload/file`"
|
||||
:headers="uploadHeaders"
|
||||
:data="{ type: 0 }"
|
||||
@before-upload="beforeUpload"
|
||||
@finish="finish"
|
||||
name="file"
|
||||
:max="20"
|
||||
:default-file-list="fileList"
|
||||
list-type="image"
|
||||
>
|
||||
<n-upload-dragger>
|
||||
<div style="margin-bottom: 12px">
|
||||
<n-icon size="48" :depth="3">
|
||||
<FileAddOutlined />
|
||||
</n-icon>
|
||||
</div>
|
||||
<n-text style="font-size: 16px"> 点击或者拖动文件到该区域来上传</n-text>
|
||||
@@ -82,125 +124,38 @@
|
||||
import { h, reactive, ref } from 'vue';
|
||||
import { UploadFileInfo, useDialog, useMessage } from 'naive-ui';
|
||||
import { BasicTable, TableAction } from '@/components/Table';
|
||||
import { BasicForm, FormSchema, useForm } from '@/components/Form/index';
|
||||
import { Delete, Edit, List, Status } from '@/api/apply/attachment';
|
||||
import { columns } from './columns';
|
||||
import { DeleteOutlined, UploadOutlined } from '@vicons/antd';
|
||||
import { statusActions, statusOptions } from '@/enums/optionsiEnum';
|
||||
import { BasicForm, useForm } from '@/components/Form/index';
|
||||
import { Delete, List } from '@/api/apply/attachment';
|
||||
import { columns, schemas } from './columns';
|
||||
import {
|
||||
DeleteOutlined,
|
||||
UploadOutlined,
|
||||
FileAddOutlined,
|
||||
CloudUploadOutlined,
|
||||
} from '@vicons/antd';
|
||||
import { useGlobSetting } from '@/hooks/setting';
|
||||
import { useUserStoreWidthOut } from '@/store/modules/user';
|
||||
import componentSetting from '@/settings/componentSetting';
|
||||
import { ResultEnum } from '@/enums/httpEnum';
|
||||
|
||||
const useUserStore = useUserStoreWidthOut();
|
||||
|
||||
const globSetting = useGlobSetting();
|
||||
|
||||
const { uploadUrl } = globSetting;
|
||||
|
||||
const urlPrefix = globSetting.urlPrefix || '';
|
||||
const uploadHeaders = reactive({
|
||||
Authorization: useUserStore.token,
|
||||
});
|
||||
|
||||
const fileList = ref<UploadFileInfo[]>([
|
||||
// {
|
||||
// id: 'c',
|
||||
// name: '图片.png',
|
||||
// status: 'finished',
|
||||
// url: 'https://07akioni.oss-cn-beijing.aliyuncs.com/07akioni.jpeg',
|
||||
// },
|
||||
]);
|
||||
|
||||
const driveOptions = [
|
||||
{
|
||||
value: 'local',
|
||||
label: '本地',
|
||||
},
|
||||
].map((s) => {
|
||||
return s;
|
||||
});
|
||||
|
||||
const params = ref({
|
||||
pageSize: 10,
|
||||
title: '',
|
||||
content: '',
|
||||
status: null,
|
||||
});
|
||||
|
||||
const rules = {
|
||||
title: {
|
||||
// required: true,
|
||||
trigger: ['blur', 'input'],
|
||||
message: '请输入标题',
|
||||
},
|
||||
};
|
||||
|
||||
const schemas: FormSchema[] = [
|
||||
{
|
||||
field: 'member_id',
|
||||
component: 'NInput',
|
||||
label: '用户ID',
|
||||
componentProps: {
|
||||
placeholder: '请输入用户ID',
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
rules: [{ message: '请输入用户ID', trigger: ['blur'] }],
|
||||
},
|
||||
{
|
||||
field: 'drive',
|
||||
component: 'NSelect',
|
||||
label: '驱动',
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
placeholder: '请选择驱动',
|
||||
options: driveOptions,
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
component: 'NSelect',
|
||||
label: '状态',
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
placeholder: '请选择类型',
|
||||
options: statusOptions,
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const fileList = ref<UploadFileInfo[]>([]);
|
||||
const message = useMessage();
|
||||
const actionRef = ref();
|
||||
const dialog = useDialog();
|
||||
const showFileModal = ref(false);
|
||||
const showModal = ref(false);
|
||||
const formBtnLoading = ref(false);
|
||||
const searchFormRef = ref({});
|
||||
const formRef = ref({});
|
||||
const searchFormRef = ref<any>({});
|
||||
const batchDeleteDisabled = ref(true);
|
||||
const checkedIds = ref([]);
|
||||
|
||||
const resetFormParams = {
|
||||
basicLogo: '',
|
||||
id: 0,
|
||||
title: '',
|
||||
name: '',
|
||||
type: 1,
|
||||
receiver: '',
|
||||
remark: '',
|
||||
sort: 0,
|
||||
status: 1,
|
||||
created_at: '',
|
||||
updated_at: '',
|
||||
};
|
||||
let formParams = ref(resetFormParams);
|
||||
|
||||
const actionColumn = reactive({
|
||||
width: 220,
|
||||
title: '操作',
|
||||
@@ -211,18 +166,14 @@
|
||||
style: 'button',
|
||||
actions: [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
label: '下载',
|
||||
onClick: handleDown.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
onClick: handleDelete.bind(null, record),
|
||||
},
|
||||
],
|
||||
dropDownActions: statusActions,
|
||||
select: (key) => {
|
||||
updateStatus(record.id, key);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -234,22 +185,23 @@
|
||||
});
|
||||
|
||||
function addTable() {
|
||||
showFileModal.value = false;
|
||||
showModal.value = true;
|
||||
fileList.value = [];
|
||||
}
|
||||
|
||||
function addFileTable() {
|
||||
showModal.value = false;
|
||||
showFileModal.value = true;
|
||||
fileList.value = [];
|
||||
}
|
||||
|
||||
const loadDataTable = async (res) => {
|
||||
return await List({ ...params.value, ...res, ...searchFormRef.value.formModel });
|
||||
return await List({ ...res, ...searchFormRef.value?.formModel });
|
||||
};
|
||||
|
||||
function onCheckedRow(rowKeys) {
|
||||
console.log(rowKeys);
|
||||
if (rowKeys.length > 0) {
|
||||
batchDeleteDisabled.value = false;
|
||||
} else {
|
||||
batchDeleteDisabled.value = true;
|
||||
}
|
||||
|
||||
batchDeleteDisabled.value = rowKeys.length <= 0;
|
||||
checkedIds.value = rowKeys;
|
||||
}
|
||||
|
||||
@@ -257,58 +209,25 @@
|
||||
actionRef.value.reload();
|
||||
}
|
||||
|
||||
function confirmForm(e) {
|
||||
e.preventDefault();
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('formParams:' + JSON.stringify(formParams.value));
|
||||
Edit(formParams.value)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
reloadTable();
|
||||
formParams.value = ref(resetFormParams);
|
||||
});
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
});
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
formBtnLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
showModal.value = true;
|
||||
formParams.value = record;
|
||||
function handleDown(record: Recordable) {
|
||||
window.open(record.fileUrl);
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
console.log('点击了删除', record);
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
// message.error(e.message ?? '操作失败');
|
||||
});
|
||||
Delete(record).then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -318,51 +237,29 @@
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete({ id: checkedIds.value })
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
});
|
||||
Delete({ id: checkedIds.value }).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleSubmit(values: Recordable) {
|
||||
console.log(values);
|
||||
params.value = values;
|
||||
function handleSubmit(_values: Recordable) {
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
function handleReset(values: Recordable) {
|
||||
params.value = values;
|
||||
function handleReset(_values: Recordable) {
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
function updateStatus(id, status) {
|
||||
Status({ id: id, status: status })
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
reloadTable({});
|
||||
});
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
});
|
||||
}
|
||||
|
||||
//上传之前
|
||||
function beforeUpload({ file }) {
|
||||
function beforeUpload({ _file }) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:openChecked="true"
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
@@ -133,7 +134,7 @@
|
||||
].map((s) => {
|
||||
return s;
|
||||
});
|
||||
const params = ref({
|
||||
const params = ref<any>({
|
||||
pageSize: 10,
|
||||
title: '',
|
||||
content: '',
|
||||
@@ -193,8 +194,8 @@
|
||||
const dialog = useDialog();
|
||||
const showModal = ref(false);
|
||||
const formBtnLoading = ref(false);
|
||||
const searchFormRef = ref({});
|
||||
const formRef = ref({});
|
||||
const searchFormRef = ref<any>({});
|
||||
const formRef = ref<any>({});
|
||||
const batchDeleteDisabled = ref(true);
|
||||
const checkedIds = ref([]);
|
||||
|
||||
@@ -210,7 +211,7 @@
|
||||
created_at: '',
|
||||
updated_at: '',
|
||||
};
|
||||
let formParams = ref(resetFormParams);
|
||||
let formParams = ref<any>(resetFormParams);
|
||||
|
||||
const actionColumn = reactive({
|
||||
width: 220,
|
||||
@@ -250,11 +251,10 @@
|
||||
}
|
||||
|
||||
const loadDataTable = async (res) => {
|
||||
return await List({ ...params.value, ...res, ...searchFormRef.value.formModel });
|
||||
return await List({ ...params.value, ...res, ...searchFormRef.value?.formModel });
|
||||
};
|
||||
|
||||
function onCheckedRow(rowKeys) {
|
||||
console.log(rowKeys);
|
||||
if (rowKeys.length > 0) {
|
||||
batchDeleteDisabled.value = false;
|
||||
} else {
|
||||
@@ -273,20 +273,14 @@
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('formParams:' + JSON.stringify(formParams.value));
|
||||
Edit(formParams.value)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
reloadTable();
|
||||
formParams.value = ref(resetFormParams);
|
||||
});
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
Edit(formParams.value).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
reloadTable();
|
||||
formParams.value = ref(resetFormParams);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
@@ -295,31 +289,24 @@
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
showModal.value = true;
|
||||
formParams.value = record;
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
console.log('点击了删除', record);
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
// message.error(e.message ?? '操作失败');
|
||||
});
|
||||
Delete(record).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -329,26 +316,20 @@
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete({ id: checkedIds.value })
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
});
|
||||
Delete({ id: checkedIds.value }).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleSubmit(values: Recordable) {
|
||||
console.log(values);
|
||||
params.value = values;
|
||||
reloadTable();
|
||||
}
|
||||
@@ -359,17 +340,12 @@
|
||||
}
|
||||
|
||||
function updateStatus(id, status) {
|
||||
Status({ id: id, status: status })
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
reloadTable({});
|
||||
});
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
Status({ id: id, status: status }).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
reloadTable();
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { h } from 'vue';
|
||||
import { NAvatar, NTag } from 'naive-ui';
|
||||
import { NTag } from 'naive-ui';
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:openChecked="true"
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
@@ -133,7 +134,7 @@
|
||||
].map((s) => {
|
||||
return s;
|
||||
});
|
||||
const params = ref({
|
||||
const params = ref<any>({
|
||||
pageSize: 10,
|
||||
title: '',
|
||||
content: '',
|
||||
@@ -193,8 +194,8 @@
|
||||
const dialog = useDialog();
|
||||
const showModal = ref(false);
|
||||
const formBtnLoading = ref(false);
|
||||
const searchFormRef = ref({});
|
||||
const formRef = ref({});
|
||||
const searchFormRef = ref<any>({});
|
||||
const formRef = ref<any>({});
|
||||
const batchDeleteDisabled = ref(true);
|
||||
const checkedIds = ref([]);
|
||||
|
||||
@@ -210,7 +211,7 @@
|
||||
created_at: '',
|
||||
updated_at: '',
|
||||
};
|
||||
let formParams = ref(resetFormParams);
|
||||
let formParams = ref<any>(resetFormParams);
|
||||
|
||||
const actionColumn = reactive({
|
||||
width: 220,
|
||||
@@ -250,11 +251,10 @@
|
||||
}
|
||||
|
||||
const loadDataTable = async (res) => {
|
||||
return await List({ ...params.value, ...res, ...searchFormRef.value.formModel });
|
||||
return await List({ ...params.value, ...res, ...searchFormRef.value?.formModel });
|
||||
};
|
||||
|
||||
function onCheckedRow(rowKeys) {
|
||||
console.log(rowKeys);
|
||||
if (rowKeys.length > 0) {
|
||||
batchDeleteDisabled.value = false;
|
||||
} else {
|
||||
@@ -273,10 +273,8 @@
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('formParams:' + JSON.stringify(formParams.value));
|
||||
Edit(formParams.value)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
@@ -295,31 +293,24 @@
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
showModal.value = true;
|
||||
formParams.value = record;
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
console.log('点击了删除', record);
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
// message.error(e.message ?? '操作失败');
|
||||
});
|
||||
Delete(record).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -329,20 +320,15 @@
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete({ id: checkedIds.value })
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
});
|
||||
Delete({ id: checkedIds.value }).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -359,17 +345,12 @@
|
||||
}
|
||||
|
||||
function updateStatus(id, status) {
|
||||
Status({ id: id, status: status })
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
reloadTable({});
|
||||
});
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
Status({ id: id, status: status }).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
reloadTable();
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
147
web/src/views/curdDemo/edit.vue
Normal file
147
web/src/views/curdDemo/edit.vue
Normal file
@@ -0,0 +1,147 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-modal
|
||||
v-model:show="isShowModal"
|
||||
:show-icon="false"
|
||||
preset="dialog"
|
||||
:title="params?.id > 0 ? '编辑 #' + params?.id : '新建'"
|
||||
:style="{
|
||||
width: dialogWidth,
|
||||
}"
|
||||
>
|
||||
<n-form
|
||||
:model="params"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
label-placement="left"
|
||||
:label-width="80"
|
||||
class="py-4"
|
||||
>
|
||||
<n-form-item label="分类ID" path="categoryId">
|
||||
<n-input-number placeholder="请输入分类ID" v-model:value="params.categoryId" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="标题" path="title">
|
||||
<n-input placeholder="请输入标题" v-model:value="params.title" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="描述" path="description">
|
||||
<n-input type="textarea" placeholder="描述" v-model:value="params.description" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="内容" path="content">
|
||||
<Editor style="height: 450px" v-model:value="params.content" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="单图" path="image">
|
||||
<UploadImage :maxNumber="1" v-model:value="params.image" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="附件" path="attachfile">
|
||||
<UploadFile :maxNumber="1" v-model:value="params.attachfile" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="显示开关" path="switch">
|
||||
<n-switch v-model:value="params.switch" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="排序" path="sort">
|
||||
<n-input-number placeholder="请输入排序" v-model:value="params.sort" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="状态" path="status">
|
||||
<n-select v-model:value="params.status" :options="options.sys_normal_disable" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
<template #action>
|
||||
<n-space>
|
||||
<n-button @click="closeForm">取消</n-button>
|
||||
<n-button type="info" :loading="formBtnLoading" @click="confirmForm">确定</n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, computed, watch } from 'vue';
|
||||
import { Edit, MaxSort } from '@/api/curdDemo';
|
||||
import Editor from '@/components/Editor/editor.vue';
|
||||
import UploadImage from '@/components/Upload/uploadImage.vue';
|
||||
import UploadFile from '@/components/Upload/uploadFile.vue';
|
||||
import { rules, options, State, newState } from './model';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { adaModalWidth } from '@/utils/hotgo';
|
||||
|
||||
const emit = defineEmits(['reloadTable', 'updateShowModal']);
|
||||
|
||||
interface Props {
|
||||
showModal: boolean;
|
||||
formParams?: State;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
showModal: false,
|
||||
formParams: () => {
|
||||
return newState(null);
|
||||
},
|
||||
});
|
||||
|
||||
const isShowModal = computed({
|
||||
get: () => {
|
||||
return props.showModal;
|
||||
},
|
||||
set: (value) => {
|
||||
emit('updateShowModal', value);
|
||||
},
|
||||
});
|
||||
|
||||
const params = computed(() => {
|
||||
return props.formParams;
|
||||
});
|
||||
|
||||
const message = useMessage();
|
||||
const formRef = ref<any>({});
|
||||
const dialogWidth = ref('75%');
|
||||
const formBtnLoading = ref(false);
|
||||
|
||||
function confirmForm(e) {
|
||||
e.preventDefault();
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
Edit(params.value).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
isShowModal.value = false;
|
||||
emit('reloadTable');
|
||||
});
|
||||
});
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
formBtnLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
adaModalWidth(dialogWidth);
|
||||
});
|
||||
|
||||
function closeForm() {
|
||||
isShowModal.value = false;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => params.value,
|
||||
(value) => {
|
||||
if (value.id === 0) {
|
||||
MaxSort().then((res) => {
|
||||
params.value.sort = res.sort;
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="less"></style>
|
||||
249
web/src/views/curdDemo/index.vue
Normal file
249
web/src/views/curdDemo/index.vue
Normal file
@@ -0,0 +1,249 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-card :bordered="false" class="proCard">
|
||||
<div class="n-layout-page-header">
|
||||
<n-card :bordered="false" title="生成演示列表">
|
||||
<!-- 这里有系统自动生成的CURD表格 -->
|
||||
</n-card>
|
||||
</div>
|
||||
<BasicForm
|
||||
@register="register"
|
||||
@submit="reloadTable"
|
||||
@reset="reloadTable"
|
||||
@keyup.enter="reloadTable"
|
||||
ref="searchFormRef"
|
||||
>
|
||||
<template #statusSlot="{ model, field }">
|
||||
<n-input v-model:value="model[field]" />
|
||||
</template>
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:openChecked="true"
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
ref="actionRef"
|
||||
:actionColumn="actionColumn"
|
||||
@update:checked-row-keys="onCheckedRow"
|
||||
:scroll-x="1090"
|
||||
:resizeHeightOffset="-10000"
|
||||
size="small"
|
||||
>
|
||||
<template #tableTitle>
|
||||
<n-button
|
||||
type="primary"
|
||||
@click="addTable"
|
||||
class="min-left-space"
|
||||
v-if="hasPermission(['/curdDemo/edit'])"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<PlusOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
新建
|
||||
</n-button>
|
||||
<n-button
|
||||
type="error"
|
||||
@click="handleBatchDelete"
|
||||
:disabled="batchDeleteDisabled"
|
||||
class="min-left-space"
|
||||
v-if="hasPermission(['/curdDemo/delete'])"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<DeleteOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
批量删除
|
||||
</n-button>
|
||||
<n-button
|
||||
type="primary"
|
||||
@click="handleExport"
|
||||
class="min-left-space"
|
||||
v-if="hasPermission(['/demoVar/export'])"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<ExportOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
导出
|
||||
</n-button>
|
||||
</template>
|
||||
</BasicTable>
|
||||
</n-card>
|
||||
<Edit
|
||||
@reloadTable="reloadTable"
|
||||
@updateShowModal="updateShowModal"
|
||||
:showModal="showModal"
|
||||
:formParams="formParams"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { h, reactive, ref } from 'vue';
|
||||
import { useDialog, useMessage } from 'naive-ui';
|
||||
import { BasicTable, TableAction } from '@/components/Table';
|
||||
import { BasicForm, useForm } from '@/components/Form/index';
|
||||
import { usePermission } from '@/hooks/web/usePermission';
|
||||
import { Delete, List, Status, Export } from '@/api/curdDemo';
|
||||
import { State, columns, schemas, options, newState } from './model';
|
||||
import { DeleteOutlined, PlusOutlined, ExportOutlined } from '@vicons/antd';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { getOptionLabel } from '@/utils/hotgo';
|
||||
import Edit from './edit.vue';
|
||||
const { hasPermission } = usePermission();
|
||||
const router = useRouter();
|
||||
const actionRef = ref();
|
||||
const dialog = useDialog();
|
||||
const message = useMessage();
|
||||
const searchFormRef = ref<any>({});
|
||||
const batchDeleteDisabled = ref(true);
|
||||
const checkedIds = ref([]);
|
||||
const showModal = ref(false);
|
||||
const formParams = ref<State>();
|
||||
|
||||
const actionColumn = reactive({
|
||||
width: 300,
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
// fixed: 'right',
|
||||
render(record) {
|
||||
return h(TableAction as any, {
|
||||
style: 'button',
|
||||
actions: [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
auth: ['/curdDemo/edit'],
|
||||
},
|
||||
{
|
||||
label: '禁用',
|
||||
onClick: handleStatus.bind(null, record, 2),
|
||||
ifShow: () => {
|
||||
return record.status === 1;
|
||||
},
|
||||
auth: ['/curdDemo/status'],
|
||||
},
|
||||
{
|
||||
label: '启用',
|
||||
onClick: handleStatus.bind(null, record, 1),
|
||||
ifShow: () => {
|
||||
return record.status === 2;
|
||||
},
|
||||
auth: ['/curdDemo/status'],
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
onClick: handleDelete.bind(null, record),
|
||||
auth: ['/curdDemo/delete'],
|
||||
},
|
||||
],
|
||||
dropDownActions: [
|
||||
{
|
||||
label: '查看详情',
|
||||
key: 'view',
|
||||
auth: ['/curdDemo/view'],
|
||||
},
|
||||
],
|
||||
select: (key) => {
|
||||
if (key === 'view') {
|
||||
return handleView(record);
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const [register, {}] = useForm({
|
||||
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
|
||||
labelWidth: 80,
|
||||
schemas,
|
||||
});
|
||||
|
||||
const loadDataTable = async (res) => {
|
||||
return await List({ ...searchFormRef.value?.formModel, ...res });
|
||||
};
|
||||
|
||||
function addTable() {
|
||||
showModal.value = true;
|
||||
formParams.value = newState(null);
|
||||
}
|
||||
|
||||
function updateShowModal(value) {
|
||||
showModal.value = value;
|
||||
}
|
||||
|
||||
function onCheckedRow(rowKeys) {
|
||||
batchDeleteDisabled.value = rowKeys.length <= 0;
|
||||
checkedIds.value = rowKeys;
|
||||
}
|
||||
|
||||
function reloadTable() {
|
||||
actionRef.value.reload();
|
||||
}
|
||||
|
||||
function handleView(record: Recordable) {
|
||||
router.push({ name: 'curdDemoView', params: { id: record.id } });
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
showModal.value = true;
|
||||
formParams.value = newState(record as State);
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record).then((_res) => {
|
||||
message.success('删除成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleBatchDelete() {
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要批量删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete({ id: checkedIds.value }).then((_res) => {
|
||||
message.success('删除成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleExport() {
|
||||
message.loading('正在导出列表...', { duration: 1200 });
|
||||
Export(searchFormRef.value?.formModel);
|
||||
}
|
||||
|
||||
function handleStatus(record: Recordable, status: number) {
|
||||
Status({ id: record.id, status: status }).then((_res) => {
|
||||
message.success('设为' + getOptionLabel(options.value.sys_normal_disable, status) + '成功');
|
||||
setTimeout(() => {
|
||||
reloadTable();
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
242
web/src/views/curdDemo/model.ts
Normal file
242
web/src/views/curdDemo/model.ts
Normal file
@@ -0,0 +1,242 @@
|
||||
import { h, ref } from 'vue';
|
||||
import { NAvatar, NImage, NTag, NSwitch, NRate } from 'naive-ui';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { FormSchema } from '@/components/Form';
|
||||
import { Dicts } from '@/api/dict/dict';
|
||||
import { Switch } from '@/api/curdDemo';
|
||||
import { isArray, isNullObject } from '@/utils/is';
|
||||
import { getFileExt } from '@/utils/urlUtils';
|
||||
import { defRangeShortcuts, defShortcuts, formatToDate } from '@/utils/dateUtil';
|
||||
import { validate } from '@/utils/validateUtil';
|
||||
import { getOptionLabel, getOptionTag, Options } from '@/utils/hotgo';
|
||||
|
||||
import { usePermission } from '@/hooks/web/usePermission';
|
||||
const { hasPermission } = usePermission();
|
||||
const $message = window['$message'];
|
||||
|
||||
|
||||
export interface State {
|
||||
id: number;
|
||||
categoryId: number;
|
||||
title: string;
|
||||
description: string;
|
||||
content: string;
|
||||
image: string;
|
||||
attachfile: string;
|
||||
switch: number;
|
||||
sort: number;
|
||||
status: number;
|
||||
createdBy: number;
|
||||
updatedBy: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
deletedAt: string;
|
||||
}
|
||||
|
||||
export const defaultState = {
|
||||
id: 0,
|
||||
categoryId: 0,
|
||||
title: '',
|
||||
description: '',
|
||||
content: '',
|
||||
image: '',
|
||||
attachfile: '',
|
||||
switch: 1,
|
||||
sort: 0,
|
||||
status: 1,
|
||||
createdBy: 0,
|
||||
updatedBy: 0,
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
deletedAt: '',
|
||||
};
|
||||
|
||||
export function newState(state: State | null): State {
|
||||
if (state !== null) {
|
||||
return cloneDeep(state);
|
||||
}
|
||||
return cloneDeep(defaultState);
|
||||
}
|
||||
|
||||
export const options = ref<Options>({
|
||||
sys_normal_disable: [],
|
||||
});
|
||||
|
||||
export const rules = {
|
||||
};
|
||||
|
||||
export const schemas = ref<FormSchema[]>([
|
||||
{
|
||||
field: 'id',
|
||||
component: 'NInputNumber',
|
||||
label: 'ID',
|
||||
componentProps: {
|
||||
placeholder: '请输入ID',
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
component: 'NSelect',
|
||||
label: '状态',
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
placeholder: '请选择状态',
|
||||
options: [],
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'createdAt',
|
||||
component: 'NDatePicker',
|
||||
label: '创建时间',
|
||||
componentProps: {
|
||||
type: 'datetimerange',
|
||||
clearable: true,
|
||||
shortcuts: defRangeShortcuts(),
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'testCategoryName',
|
||||
component: 'NInput',
|
||||
label: '分类名称',
|
||||
componentProps: {
|
||||
placeholder: '请输入分类名称',
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'id',
|
||||
},
|
||||
{
|
||||
title: '分类ID',
|
||||
key: 'categoryId',
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
key: 'title',
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
key: 'description',
|
||||
},
|
||||
{
|
||||
title: '单图',
|
||||
key: 'image',
|
||||
render(row) {
|
||||
return h(NImage, {
|
||||
width: 32,
|
||||
height: 32,
|
||||
src: row.image,
|
||||
style: {
|
||||
width: '32px',
|
||||
height: '32px',
|
||||
'max-width': '100%',
|
||||
'max-height': '100%',
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '附件',
|
||||
key: 'attachfile',
|
||||
render(row) {
|
||||
if (row.attachfile === '') {
|
||||
return ``;
|
||||
}
|
||||
return h(
|
||||
NAvatar,
|
||||
{
|
||||
size: 'small',
|
||||
},
|
||||
{
|
||||
default: () => getFileExt(row.attachfile),
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '显示开关',
|
||||
key: 'switch',
|
||||
width: 100,
|
||||
render(row) {
|
||||
return h(NSwitch, {
|
||||
value: row.switch === 1,
|
||||
checked: '开启',
|
||||
unchecked: '关闭',
|
||||
disabled: !hasPermission(['/curdDemo/switch']),
|
||||
onUpdateValue: function (e) {
|
||||
console.log('onUpdateValue e:' + JSON.stringify(e));
|
||||
row.switch = e ? 1 : 2;
|
||||
Switch({ id: row.id, key: 'switch', value: row.switch }).then((_res) => {
|
||||
$message.success('操作成功');
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
key: 'sort',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
render(row) {
|
||||
if (isNullObject(row.status)) {
|
||||
return ``;
|
||||
}
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
type: getOptionTag(options.value.sys_normal_disable, row.status),
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => getOptionLabel(options.value.sys_normal_disable, row.status),
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createdAt',
|
||||
},
|
||||
{
|
||||
title: '分类名称',
|
||||
key: 'testCategoryName',
|
||||
},
|
||||
];
|
||||
|
||||
async function loadOptions() {
|
||||
options.value = await Dicts({
|
||||
types: [
|
||||
'sys_normal_disable',
|
||||
],
|
||||
});
|
||||
for (const item of schemas.value) {
|
||||
switch (item.field) {
|
||||
case 'status':
|
||||
item.componentProps.options = options.value.sys_normal_disable;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await loadOptions();
|
||||
108
web/src/views/curdDemo/view.vue
Normal file
108
web/src/views/curdDemo/view.vue
Normal file
@@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="n-layout-page-header">
|
||||
<n-card :bordered="false" title="生成演示详情"> <!-- CURD详情页--> </n-card>
|
||||
</div>
|
||||
<n-card :bordered="false" class="proCard mt-4" size="small" :segmented="{ content: true }">
|
||||
<n-descriptions label-placement="left" class="py-2" column="4">
|
||||
<n-descriptions-item>
|
||||
<template #label>分类ID</template>
|
||||
{{ formValue.categoryId }}
|
||||
</n-descriptions-item>
|
||||
|
||||
<n-descriptions-item>
|
||||
<template #label>标题</template>
|
||||
{{ formValue.title }}
|
||||
</n-descriptions-item>
|
||||
|
||||
<n-descriptions-item>
|
||||
<template #label>描述</template>
|
||||
<span v-html="formValue.description"></span></n-descriptions-item>
|
||||
|
||||
<n-descriptions-item>
|
||||
<template #label>内容</template>
|
||||
<span v-html="formValue.content"></span></n-descriptions-item>
|
||||
|
||||
<n-descriptions-item>
|
||||
<template #label>单图</template>
|
||||
<n-image style="margin-left: 10px; height: 100px; width: 100px" :src="formValue.image"
|
||||
/></n-descriptions-item>
|
||||
|
||||
<n-descriptions-item>
|
||||
<template #label>附件</template>
|
||||
<div
|
||||
class="upload-card"
|
||||
v-show="formValue.attachfile !== ''"
|
||||
@click="download(formValue.attachfile)"
|
||||
>
|
||||
<div class="upload-card-item" style="height: 100px; width: 100px">
|
||||
<div class="upload-card-item-info">
|
||||
<div class="img-box">
|
||||
<n-avatar :style="fileAvatarCSS">{{ getFileExt(formValue.attachfile) }}</n-avatar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</n-descriptions-item>
|
||||
|
||||
<n-descriptions-item label="显示开关">
|
||||
<n-switch v-model:value="formValue.switch" :unchecked-value="2" :checked-value="1" :disabled="true"
|
||||
/></n-descriptions-item>
|
||||
|
||||
<n-descriptions-item>
|
||||
<template #label>排序</template>
|
||||
{{ formValue.sort }}
|
||||
</n-descriptions-item>
|
||||
|
||||
<n-descriptions-item label="状态">
|
||||
<template v-for="(item, key) in formValue?.status" :key="key">
|
||||
<n-tag
|
||||
:type="getOptionTag(options.sys_normal_disable, item)"
|
||||
size="small"
|
||||
class="min-left-space"
|
||||
>{{ getOptionLabel(options.sys_normal_disable, item) }}</n-tag
|
||||
>
|
||||
</template>
|
||||
</n-descriptions-item>
|
||||
|
||||
|
||||
</n-descriptions>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { View } from '@/api/curdDemo';
|
||||
import { newState, options } from './model';
|
||||
import { getOptionLabel, getOptionTag } from '@/utils/hotgo';
|
||||
import { getFileExt } from '@/utils/urlUtils';
|
||||
|
||||
const message = useMessage();
|
||||
const router = useRouter();
|
||||
const id = Number(router.currentRoute.value.params.id);
|
||||
const formValue = ref(newState(null));
|
||||
const fileAvatarCSS = computed(() => {
|
||||
return {
|
||||
'--n-merged-size': `var(--n-avatar-size-override, 80px)`,
|
||||
'--n-font-size': `18px`,
|
||||
};
|
||||
});
|
||||
|
||||
//下载
|
||||
function download(url: string) {
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (id < 1) {
|
||||
message.error('ID不正确,请检查!');
|
||||
return;
|
||||
}
|
||||
formValue.value = await View({ id: id });
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
509
web/src/views/develop/code/components/BaseInfo.vue
Normal file
509
web/src/views/develop/code/components/BaseInfo.vue
Normal file
@@ -0,0 +1,509 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-card
|
||||
:bordered="true"
|
||||
title="基本设置"
|
||||
class="proCard mt-2"
|
||||
size="small"
|
||||
:segmented="{ content: true }"
|
||||
>
|
||||
<n-form ref="formRef" :model="formValue">
|
||||
<n-row :gutter="24">
|
||||
<n-col :span="6" style="min-width: 200px">
|
||||
<n-form-item label="生成类型" path="title">
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="selectList.genType"
|
||||
v-model:value="formValue.genType"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="6" style="min-width: 200px">
|
||||
<n-form-item label="实体命名" path="varName">
|
||||
<n-input placeholder="请输入" v-model:value="formValue.varName" />
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="6" style="min-width: 200px">
|
||||
<n-form-item
|
||||
label="数据库"
|
||||
path="dbName"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="selectList.db"
|
||||
v-model:value="formValue.dbName"
|
||||
@update:value="handleDbUpdateValue"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="6" style="min-width: 200px">
|
||||
<n-form-item
|
||||
label="数据库表"
|
||||
path="tableName"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-select
|
||||
filterable
|
||||
tag
|
||||
:loading="tablesLoading"
|
||||
placeholder="请选择"
|
||||
:options="tablesOption"
|
||||
v-model:value="formValue.tableName"
|
||||
@update:value="handleTableUpdateValue"
|
||||
:disabled="formValue.dbName === ''"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="18">
|
||||
<n-form-item
|
||||
label="表格头部按钮组"
|
||||
path="tableName"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-checkbox-group v-model:value="formValue.options.headOps">
|
||||
<n-space item-style="display: flex;">
|
||||
<n-checkbox value="add" label="新增表单按钮" />
|
||||
<n-checkbox value="batchDel" label="批量删除按钮" />
|
||||
<n-checkbox value="export" label="导出按钮" />
|
||||
</n-space>
|
||||
</n-checkbox-group>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="24">
|
||||
<n-form-item
|
||||
label="表格列操作"
|
||||
path="columnOps"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-checkbox-group v-model:value="formValue.options.columnOps">
|
||||
<n-space item-style="display: flex;">
|
||||
<n-checkbox value="edit" label="编辑" />
|
||||
<n-checkbox value="status" label="状态修改" />
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
|
||||
<QuestionCircleOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<span>主表中存在`status`字段时才会生效</span>
|
||||
</n-popover>
|
||||
<n-checkbox value="del" label="删除" />
|
||||
<n-checkbox value="view" label="详情页" />
|
||||
<n-checkbox value="check" label="开启勾选列" />
|
||||
<n-checkbox value="switch" label="操作开关" />
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
|
||||
<QuestionCircleOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<span>主表中存在`switch`字段时才会生效</span>
|
||||
</n-popover>
|
||||
</n-space>
|
||||
</n-checkbox-group>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="24">
|
||||
<n-form-item
|
||||
label="自动化操作"
|
||||
path="autoOps"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-checkbox-group v-model:value="formValue.options.autoOps">
|
||||
<n-space item-style="display: flex;">
|
||||
<n-checkbox value="genMenuPermissions" label="生成菜单权限" />
|
||||
<n-checkbox value="runDao" label="生成前运行 [gf gen dao]" />
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
|
||||
<QuestionCircleOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<span>请确保运行环境已安装gf命令</span>
|
||||
</n-popover>
|
||||
<n-checkbox value="runService" label="生成后运行 [gf gen service]" />
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
|
||||
<QuestionCircleOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<span>请确保运行环境已安装gf命令</span>
|
||||
</n-popover>
|
||||
<n-checkbox value="forcedCover" label="强制覆盖" />
|
||||
<n-popover trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon size="15" class="tips-help-icon" color="#2d8cf0">
|
||||
<QuestionCircleOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
<span>只会强制覆盖需要生成的文件,但不包含SQL文件</span>
|
||||
</n-popover>
|
||||
</n-space>
|
||||
</n-checkbox-group>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col
|
||||
:span="6"
|
||||
style="min-width: 200px"
|
||||
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
|
||||
>
|
||||
<n-form-item label="上级菜单" path="pid">
|
||||
<n-tree-select
|
||||
:options="optionMenuTree"
|
||||
:value="formValue.options.menu.pid"
|
||||
@update:value="handleUpdateMenuPid"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col
|
||||
:span="6"
|
||||
style="min-width: 200px"
|
||||
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
|
||||
>
|
||||
<n-form-item label="菜单名称" path="tableComment">
|
||||
<n-input placeholder="请输入" v-model:value="formValue.tableComment" />
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col
|
||||
:span="6"
|
||||
style="min-width: 200px"
|
||||
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
|
||||
>
|
||||
<n-form-item label="菜单图标" path="menuIcon">
|
||||
<IconSelector style="width: 100%" v-model:value="formValue.options.menu.icon" />
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col
|
||||
:span="6"
|
||||
style="min-width: 200px"
|
||||
v-show="formValue.options?.autoOps?.includes('genMenuPermissions')"
|
||||
>
|
||||
<n-form-item label="菜单排序" path="menuIcon">
|
||||
<n-input-number
|
||||
style="width: 100%"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.options.menu.sort"
|
||||
clearable
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
</n-row>
|
||||
</n-form>
|
||||
</n-card>
|
||||
|
||||
<n-card
|
||||
:bordered="true"
|
||||
title="关联表设置"
|
||||
class="proCard mt-2"
|
||||
size="small"
|
||||
:segmented="{ content: true }"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<template #header-extra>
|
||||
<n-space>
|
||||
<n-button type="warning" @click="addJoin" :disabled="formValue.options?.join?.length >= 3"
|
||||
>新增关联表</n-button
|
||||
>
|
||||
</n-space>
|
||||
</template>
|
||||
|
||||
<n-form ref="formRef" :model="formValue">
|
||||
<n-alert :show-icon="false">关联表数量建议在三个以下</n-alert>
|
||||
|
||||
<n-row :gutter="6" v-for="(join, index) in formValue.options.join" :key="index">
|
||||
<n-col :span="6" style="min-width: 200px">
|
||||
<n-form-item label="关联表" path="join.linkTable">
|
||||
<n-select
|
||||
filterable
|
||||
tag
|
||||
:loading="tablesLoading"
|
||||
placeholder="请选择"
|
||||
:options="linkTablesOption"
|
||||
v-model:value="join.linkTable"
|
||||
@update:value="handleLinkTableUpdateValue(join)"
|
||||
:disabled="formValue.dbName === ''"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="3" style="min-width: 100px">
|
||||
<n-form-item
|
||||
label="别名"
|
||||
path="join.alias"
|
||||
v-show="formValue.genType >= 10 && formValue.genType < 20"
|
||||
>
|
||||
<n-input
|
||||
placeholder="请输入"
|
||||
v-model:value="join.alias"
|
||||
@update:value="updateJoinAlias"
|
||||
/>
|
||||
|
||||
<template #feedback> {{ joinAliasFeedback }}</template>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="3" style="min-width: 100px">
|
||||
<n-form-item label="关联方式" path="join.linkMode">
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="selectList.linkMode"
|
||||
v-model:value="join.linkMode"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
<n-col :span="5" style="min-width: 180px">
|
||||
<n-form-item label="关联字段" path="join.field">
|
||||
<n-select
|
||||
filterable
|
||||
tag
|
||||
:loading="linkColumnsLoading"
|
||||
placeholder="请选择"
|
||||
:options="linkColumnsOption[join.uuid]"
|
||||
v-model:value="join.field"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="5" style="min-width: 180px">
|
||||
<n-form-item label="主表关联字段" path="join.masterField">
|
||||
<n-select
|
||||
filterable
|
||||
tag
|
||||
:loading="columnsLoading"
|
||||
placeholder="请选择"
|
||||
:options="columnsOption"
|
||||
v-model:value="join.masterField"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-col>
|
||||
|
||||
<n-col :span="2" style="min-width: 50px">
|
||||
<n-space>
|
||||
<n-form-item label="操作" path="title">
|
||||
<n-button @click="delJoin(join, index)" size="small" strong secondary type="error"
|
||||
>移除</n-button
|
||||
>
|
||||
</n-form-item>
|
||||
</n-space>
|
||||
</n-col>
|
||||
</n-row>
|
||||
</n-form>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, computed, watch } from 'vue';
|
||||
import { FormInst } from 'naive-ui';
|
||||
import { newState, selectListObj } from './model';
|
||||
import { TableSelect, ColumnSelect } from '@/api/develop/code';
|
||||
import { getRandomString } from '@/utils/charset';
|
||||
import IconSelector from '@/components/IconSelector/index.vue';
|
||||
import { QuestionCircleOutlined } from '@vicons/antd';
|
||||
import { getMenuList } from '@/api/system/menu';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { isLetterBegin } from '@/utils/is';
|
||||
|
||||
const formRef = ref<FormInst | null>(null);
|
||||
const tablesLoading = ref(false);
|
||||
const columnsLoading = ref(false);
|
||||
const linkColumnsLoading = ref(false);
|
||||
const tablesOption = ref<any>([]); // 数据库表选项
|
||||
const columnsOption = ref<any>([]); // 主表字段选项
|
||||
const linkTablesOption = ref<any>([]); // 关联表选项
|
||||
const linkColumnsOption = ref<any>([]); // 关联表字段选项
|
||||
|
||||
const optionMenuTree = ref([
|
||||
{
|
||||
id: 0,
|
||||
key: 0,
|
||||
label: '根目录',
|
||||
pid: 0,
|
||||
title: '根目录',
|
||||
type: 1,
|
||||
},
|
||||
]);
|
||||
|
||||
const emit = defineEmits(['update:value']);
|
||||
|
||||
interface Props {
|
||||
value?: any;
|
||||
selectList: any;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
value: newState(null),
|
||||
selectList: selectListObj,
|
||||
});
|
||||
|
||||
watch(props, async (newVal, oldVal) => {
|
||||
if (newVal.value.dbName != oldVal.value.dbName) {
|
||||
await instLoad();
|
||||
}
|
||||
});
|
||||
|
||||
const formValue = computed({
|
||||
get() {
|
||||
return props.value;
|
||||
},
|
||||
set(value) {
|
||||
emit('update:value', value);
|
||||
},
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(async function () {
|
||||
await instLoad();
|
||||
// 切换tab时会导致选项被清空,这里重新进行加载
|
||||
await loadLinkColumnsOption();
|
||||
await loadMenuTreeOption();
|
||||
}, 500);
|
||||
});
|
||||
|
||||
const loadMenuTreeOption = async () => {
|
||||
const options = await getMenuList();
|
||||
optionMenuTree.value = [
|
||||
{
|
||||
id: 0,
|
||||
key: 0,
|
||||
label: '根目录',
|
||||
pid: 0,
|
||||
title: '根目录',
|
||||
type: 1,
|
||||
},
|
||||
];
|
||||
optionMenuTree.value = optionMenuTree.value.concat(options.list);
|
||||
};
|
||||
|
||||
const loadSelect = async () => {
|
||||
columnsOption.value = await loadColumnSelect(formValue.value.tableName);
|
||||
};
|
||||
|
||||
async function instLoad() {
|
||||
columnsLoading.value = true;
|
||||
tablesLoading.value = true;
|
||||
await loadSelect();
|
||||
await loadTableSelect(formValue.value.dbName);
|
||||
tablesLoading.value = false;
|
||||
columnsLoading.value = false;
|
||||
}
|
||||
|
||||
async function loadLinkColumnsOption() {
|
||||
if (formValue.value.options.join === undefined) {
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < formValue.value.options.join.length; i++) {
|
||||
linkColumnsLoading.value = true;
|
||||
linkColumnsOption.value[formValue.value.options.join[i].uuid] = await loadColumnSelect(
|
||||
formValue.value.options.join[i].linkTable
|
||||
);
|
||||
linkColumnsLoading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
// 处理选项更新
|
||||
async function handleDbUpdateValue(value, _option) {
|
||||
tablesLoading.value = true;
|
||||
await loadTableSelect(value);
|
||||
tablesLoading.value = false;
|
||||
}
|
||||
|
||||
async function loadTableSelect(value) {
|
||||
const options = await TableSelect({ name: value });
|
||||
tablesOption.value = cloneDeep(options);
|
||||
linkTablesOption.value = cloneDeep(options);
|
||||
}
|
||||
|
||||
async function loadColumnSelect(value) {
|
||||
return await ColumnSelect({ name: formValue.value.dbName, table: value });
|
||||
}
|
||||
|
||||
function handleTableUpdateValue(value, option) {
|
||||
formValue.value.varName = option?.defVarName as string;
|
||||
formValue.value.daoName = option?.daoName as string;
|
||||
formValue.value.tableComment = option?.defTableComment as string;
|
||||
}
|
||||
|
||||
function addJoin() {
|
||||
if (formValue.value.options.join === undefined) {
|
||||
formValue.value.options.join = [];
|
||||
}
|
||||
let uuid = getRandomString(16, true);
|
||||
formValue.value.options.join.push({
|
||||
uuid: uuid,
|
||||
linkTable: '',
|
||||
alias: '',
|
||||
linkMode: 1,
|
||||
field: '',
|
||||
masterField: '',
|
||||
daoName: '',
|
||||
columns: [],
|
||||
});
|
||||
linkColumnsOption.value[uuid] = [];
|
||||
}
|
||||
|
||||
function delJoin(join, index) {
|
||||
formValue.value.options.join.splice(index, 1);
|
||||
delete linkColumnsOption.value[join.uuid];
|
||||
let i = linkTablesOption.value.findIndex((res) => res.value === join.linkTable);
|
||||
if (i > -1) {
|
||||
linkTablesOption.value[i].disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function handleLinkTableUpdateValue(join) {
|
||||
let i = linkTablesOption.value.findIndex((res) => res.value === join.linkTable);
|
||||
if (i > -1) {
|
||||
join.alias = linkTablesOption.value[i].defAlias;
|
||||
join.daoName = linkTablesOption.value[i].daoName;
|
||||
linkTablesOption.value[i].disabled = true;
|
||||
}
|
||||
|
||||
linkColumnsLoading.value = true;
|
||||
linkColumnsOption.value[join.uuid] = await loadColumnSelect(join.linkTable);
|
||||
// 清空更新前的字段
|
||||
join.field = '';
|
||||
linkColumnsLoading.value = false;
|
||||
}
|
||||
|
||||
const joinAliasFeedback = ref('');
|
||||
function updateJoinAlias(value: string) {
|
||||
if (value.length < 3) {
|
||||
joinAliasFeedback.value = '别名不能小于3位';
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isLetterBegin(value)) {
|
||||
joinAliasFeedback.value = '别名必须以字母开头';
|
||||
return;
|
||||
}
|
||||
joinAliasFeedback.value = '';
|
||||
}
|
||||
|
||||
function handleUpdateMenuPid(value: string | number | Array<string | number> | null) {
|
||||
formValue.value.options.menu.pid = value;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
::v-deep(.default_text_value) {
|
||||
color: var(--n-tab-text-color-active);
|
||||
}
|
||||
::v-deep(.tips-help-icon) {
|
||||
margin-left: -16px;
|
||||
margin-top: 5px;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
357
web/src/views/develop/code/components/EditMasterCell.vue
Normal file
357
web/src/views/develop/code/components/EditMasterCell.vue
Normal file
@@ -0,0 +1,357 @@
|
||||
<template>
|
||||
<n-spin :show="show" description="加载中...">
|
||||
<n-card :bordered="false" class="proCard">
|
||||
<BasicTable
|
||||
:single-line="false"
|
||||
size="small"
|
||||
:striped="true"
|
||||
:resizable="true"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:openChecked="false"
|
||||
:showTopRight="false"
|
||||
:row-key="(row) => row.id"
|
||||
ref="actionRef"
|
||||
:canResize="true"
|
||||
:resizeHeightOffset="-20000"
|
||||
:pagination="false"
|
||||
:scroll-x="1090"
|
||||
:scrollbar-props="{ trigger: 'none' }"
|
||||
/>
|
||||
</n-card>
|
||||
</n-spin>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, h, onMounted, ref } from 'vue';
|
||||
import { BasicTable } from '@/components/Table';
|
||||
import { genInfoObj, selectListObj } from '@/views/develop/code/components/model';
|
||||
import { ColumnList } from '@/api/develop/code';
|
||||
import { NButton, NCheckbox, NInput, NSelect, NTooltip, NTreeSelect } from 'naive-ui';
|
||||
import { HelpCircleOutline } from '@vicons/ionicons5';
|
||||
import { renderIcon } from '@/utils';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
const renderTooltip = (trigger, content) => {
|
||||
return h(NTooltip, null, {
|
||||
trigger: () => trigger,
|
||||
default: () => content,
|
||||
});
|
||||
};
|
||||
|
||||
const emit = defineEmits(['update:value']);
|
||||
|
||||
interface Props {
|
||||
value?: any;
|
||||
selectList: any;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
value: genInfoObj,
|
||||
selectList: selectListObj,
|
||||
});
|
||||
|
||||
const formValue = computed({
|
||||
get() {
|
||||
return props.value;
|
||||
},
|
||||
set(value) {
|
||||
emit('update:value', value);
|
||||
},
|
||||
});
|
||||
|
||||
const actionRef = ref();
|
||||
const columns = ref<any>([]);
|
||||
const show = ref(false);
|
||||
const dataSource = ref(formValue.value.masterColumns);
|
||||
onMounted(async () => {
|
||||
show.value = true;
|
||||
if (formValue.value.masterColumns.length === 0) {
|
||||
formValue.value.masterColumns = await ColumnList({
|
||||
name: formValue.value.dbName,
|
||||
table: formValue.value.tableName,
|
||||
});
|
||||
dataSource.value = formValue.value.masterColumns;
|
||||
}
|
||||
|
||||
columns.value = [
|
||||
{
|
||||
title: '位置',
|
||||
key: 'id',
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
title(_column) {
|
||||
return renderTooltip(
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
ghost: true,
|
||||
strong: true,
|
||||
size: 'small',
|
||||
text: true,
|
||||
iconPlacement: 'right',
|
||||
},
|
||||
{ default: () => '字段', icon: renderIcon(HelpCircleOutline) }
|
||||
),
|
||||
'Go类型和属性定义取决于你在/hack/config.yaml中的配置参数'
|
||||
);
|
||||
},
|
||||
key: 'field',
|
||||
align: 'center',
|
||||
width: 800,
|
||||
children: [
|
||||
{
|
||||
title: '字段列名',
|
||||
key: 'name',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '物理类型',
|
||||
key: 'sqlType',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: 'Go属性',
|
||||
key: 'goName',
|
||||
width: 130,
|
||||
},
|
||||
{
|
||||
title: 'Go类型',
|
||||
key: 'goType',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'Ts属性',
|
||||
key: 'tsName',
|
||||
width: 130,
|
||||
},
|
||||
{
|
||||
title: 'Ts类型',
|
||||
key: 'tsType',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '字段描述',
|
||||
key: 'dc',
|
||||
width: 150,
|
||||
render(row) {
|
||||
return h(NInput, {
|
||||
value: row.dc,
|
||||
onUpdateValue: function (e) {
|
||||
row.dc = e;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
width: 800,
|
||||
title(_column) {
|
||||
return renderTooltip(
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
ghost: true,
|
||||
strong: true,
|
||||
size: 'small',
|
||||
text: true,
|
||||
iconPlacement: 'right',
|
||||
},
|
||||
{ default: () => '新增/编辑表单', icon: renderIcon(HelpCircleOutline) }
|
||||
),
|
||||
'勾选编辑以后会在新增、编辑表单中显示该字段;当同时勾选列表查询时,会优先使用配置的表单组件'
|
||||
);
|
||||
},
|
||||
key: 'edit',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
align: 'center',
|
||||
title: '编辑',
|
||||
key: 'isEdit',
|
||||
width: 50,
|
||||
render(row) {
|
||||
return h(NCheckbox, {
|
||||
defaultChecked: row.isEdit,
|
||||
disabled: row.name === 'id',
|
||||
onUpdateChecked: function (e) {
|
||||
row.isEdit = e;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '必填',
|
||||
key: 'required',
|
||||
width: 50,
|
||||
align: 'center',
|
||||
render(row) {
|
||||
return h(NCheckbox, {
|
||||
defaultChecked: row.required,
|
||||
disabled: row.name === 'id',
|
||||
onUpdateChecked: function (e) {
|
||||
row.required = e;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '唯一',
|
||||
key: 'unique',
|
||||
width: 50,
|
||||
align: 'center',
|
||||
render(row) {
|
||||
return h(NCheckbox, {
|
||||
defaultChecked: row.unique,
|
||||
disabled: row.name === 'id',
|
||||
onUpdateChecked: function (e) {
|
||||
row.unique = e;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '表单组件',
|
||||
key: 'formMode',
|
||||
width: 200,
|
||||
render(row) {
|
||||
return h(NSelect, {
|
||||
value: row.formMode,
|
||||
options: getFormModeOptions(row.tsType),
|
||||
// render: function (row) {
|
||||
// return props.selectList?.formMode ?? [];
|
||||
// },
|
||||
// onFocus: function (e) {
|
||||
// console.log('表单组件 onFocus row:', e);
|
||||
// },
|
||||
onUpdateValue: function (e) {
|
||||
row.formMode = e;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '表单验证',
|
||||
key: 'formRole',
|
||||
width: 200,
|
||||
render(row) {
|
||||
return h(NSelect, {
|
||||
value: row.formRole,
|
||||
disabled: row.name === 'id',
|
||||
options: props.selectList?.formRole ?? [],
|
||||
onUpdateValue: function (e) {
|
||||
row.formRole = e;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '字典类型',
|
||||
key: 'dictType',
|
||||
width: 300,
|
||||
render(row) {
|
||||
return h(NTreeSelect, {
|
||||
value: row.dictType,
|
||||
disabled: row.name === 'id',
|
||||
options: props.selectList?.dictMode ?? [],
|
||||
onUpdateValue: function (e) {
|
||||
row.dictType = e;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
width: 800,
|
||||
title: '列表',
|
||||
key: 'list',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '列表',
|
||||
key: 'isList',
|
||||
width: 50,
|
||||
align: 'center',
|
||||
render(row) {
|
||||
return h(NCheckbox, {
|
||||
defaultChecked: row.isList,
|
||||
onUpdateChecked: function (e) {
|
||||
row.isList = e;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '导出',
|
||||
key: 'isExport',
|
||||
width: 50,
|
||||
align: 'center',
|
||||
render(row) {
|
||||
return h(NCheckbox, {
|
||||
defaultChecked: row.isExport,
|
||||
onUpdateChecked: function (e) {
|
||||
row.isExport = e;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '查询',
|
||||
key: 'isQuery',
|
||||
width: 50,
|
||||
align: 'center',
|
||||
render(row) {
|
||||
return h(NCheckbox, {
|
||||
defaultChecked: row.isQuery,
|
||||
onUpdateChecked: function (e) {
|
||||
row.isQuery = e;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '查询条件',
|
||||
key: 'queryWhere',
|
||||
width: 300,
|
||||
render(row) {
|
||||
return h(NSelect, {
|
||||
value: row.queryWhere,
|
||||
disabled: row.name === 'id',
|
||||
options: props.selectList?.whereMode ?? [],
|
||||
onUpdateValue: function (e) {
|
||||
row.queryWhere = e;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
show.value = false;
|
||||
});
|
||||
|
||||
function getFormModeOptions(type: string) {
|
||||
const options = cloneDeep(props.selectList?.formMode ?? []);
|
||||
if (options.length === 0) {
|
||||
return [];
|
||||
}
|
||||
switch (type) {
|
||||
case 'number':
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
const allows = ['InputNumber', 'Radio', 'Select', 'Switch', 'Rate'];
|
||||
if (!allows.includes(options[i].value)) {
|
||||
options[i].disabled = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
return options;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
243
web/src/views/develop/code/components/EditSlaveCell.vue
Normal file
243
web/src/views/develop/code/components/EditSlaveCell.vue
Normal file
@@ -0,0 +1,243 @@
|
||||
<template>
|
||||
<n-spin :show="show" description="加载中...">
|
||||
<n-card :bordered="false" class="proCard">
|
||||
<BasicTable
|
||||
:single-line="false"
|
||||
size="small"
|
||||
:striped="true"
|
||||
:resizable="true"
|
||||
:columns="columns"
|
||||
:dataSource="dataSource"
|
||||
:openChecked="false"
|
||||
:showTopRight="false"
|
||||
:row-key="(row) => row.id"
|
||||
ref="actionRef"
|
||||
:canResize="true"
|
||||
:resizeHeightOffset="-20000"
|
||||
:pagination="false"
|
||||
:scroll-x="1090"
|
||||
:scrollbar-props="{ trigger: 'none' }"
|
||||
/>
|
||||
</n-card>
|
||||
</n-spin>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Component, computed, h, onMounted, ref } from 'vue';
|
||||
import { BasicTable } from '@/components/Table';
|
||||
import { genInfoObj, selectListObj } from '@/views/develop/code/components/model';
|
||||
import { ColumnList } from '@/api/develop/code';
|
||||
import { NButton, NCheckbox, NIcon, NInput, NSelect, NTooltip } from 'naive-ui';
|
||||
import { HelpCircleOutline } from '@vicons/ionicons5';
|
||||
|
||||
const renderTooltip = (trigger, content) => {
|
||||
return h(NTooltip, null, {
|
||||
trigger: () => trigger,
|
||||
default: () => content,
|
||||
});
|
||||
};
|
||||
function renderIcon(icon: Component) {
|
||||
return () => h(NIcon, null, { default: () => h(icon) });
|
||||
}
|
||||
|
||||
const emit = defineEmits(['update:value']);
|
||||
|
||||
interface Props {
|
||||
value?: any;
|
||||
selectList: any;
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
value: genInfoObj,
|
||||
selectList: selectListObj,
|
||||
uuid: '',
|
||||
});
|
||||
|
||||
const columns = ref<any>([]);
|
||||
|
||||
const formValue = computed({
|
||||
get() {
|
||||
return props.value;
|
||||
},
|
||||
set(value) {
|
||||
emit('update:value', value);
|
||||
},
|
||||
});
|
||||
|
||||
function getIndex() {
|
||||
if (formValue.value.options.join.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
for (let i = 0; i < formValue.value.options.join.length; i++) {
|
||||
if (formValue.value.options.join[i].uuid === props.uuid) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
const show = ref(false);
|
||||
const dataSource = ref([]);
|
||||
onMounted(async () => {
|
||||
show.value = true;
|
||||
setTimeout(async () => {
|
||||
const index = getIndex();
|
||||
if (formValue.value.options.join[index].columns.length === 0) {
|
||||
formValue.value.options.join[index].columns = await ColumnList({
|
||||
name: formValue.value.dbName,
|
||||
table: formValue.value.options.join[index].linkTable,
|
||||
isLink: 1,
|
||||
alias: formValue.value.options.join[index].alias,
|
||||
});
|
||||
}
|
||||
|
||||
dataSource.value = formValue.value.options.join[index].columns;
|
||||
|
||||
columns.value = [
|
||||
{
|
||||
title: '位置',
|
||||
key: 'id',
|
||||
width: 50,
|
||||
},
|
||||
{
|
||||
title(_column) {
|
||||
return renderTooltip(
|
||||
h(
|
||||
NButton,
|
||||
{
|
||||
ghost: true,
|
||||
strong: true,
|
||||
size: 'small',
|
||||
text: true,
|
||||
iconPlacement: 'right',
|
||||
},
|
||||
{ default: () => '字段', icon: renderIcon(HelpCircleOutline) }
|
||||
),
|
||||
'Go类型和属性定义取决于你在/hack/config.yaml中的配置参数'
|
||||
);
|
||||
},
|
||||
key: 'field',
|
||||
align: 'center',
|
||||
width: 800,
|
||||
children: [
|
||||
{
|
||||
title: '字段列名',
|
||||
key: 'name',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '物理类型',
|
||||
key: 'sqlType',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: 'Go属性',
|
||||
key: 'goName',
|
||||
width: 260,
|
||||
},
|
||||
{
|
||||
title: 'Go类型',
|
||||
key: 'goType',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: 'Ts属性',
|
||||
key: 'tsName',
|
||||
width: 260,
|
||||
},
|
||||
{
|
||||
title: 'Ts类型',
|
||||
key: 'tsType',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '字段描述',
|
||||
key: 'dc',
|
||||
width: 150,
|
||||
render(row) {
|
||||
return h(NInput, {
|
||||
value: row.dc,
|
||||
onUpdateValue: function (e) {
|
||||
row.dc = e;
|
||||
// await saveProductCustom(row.id, 'frontShow', e);
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
width: 800,
|
||||
title: '列表',
|
||||
key: 'list',
|
||||
align: 'center',
|
||||
children: [
|
||||
{
|
||||
title: '列表',
|
||||
key: 'isList',
|
||||
width: 50,
|
||||
align: 'center',
|
||||
render(row) {
|
||||
return h(NCheckbox, {
|
||||
defaultChecked: row.isList,
|
||||
onUpdateChecked: function (e) {
|
||||
row.isList = e;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '导出',
|
||||
key: 'isExport',
|
||||
width: 50,
|
||||
align: 'center',
|
||||
render(row) {
|
||||
return h(NCheckbox, {
|
||||
defaultChecked: row.isExport,
|
||||
onUpdateChecked: function (e) {
|
||||
row.isExport = e;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '查询',
|
||||
key: 'isQuery',
|
||||
width: 50,
|
||||
align: 'center',
|
||||
render(row) {
|
||||
return h(NCheckbox, {
|
||||
defaultChecked: row.isQuery,
|
||||
onUpdateChecked: function (e) {
|
||||
row.isQuery = e;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '查询条件',
|
||||
key: 'queryWhere',
|
||||
width: 300,
|
||||
render(row) {
|
||||
return h(NSelect, {
|
||||
value: row.queryWhere,
|
||||
disabled: row.name === 'id',
|
||||
options: props.selectList?.whereMode ?? [],
|
||||
onUpdateValue: function (e) {
|
||||
row.queryWhere = e;
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
show.value = false;
|
||||
}, 50);
|
||||
});
|
||||
|
||||
const actionRef = ref();
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
84
web/src/views/develop/code/components/PreviewTab.vue
Normal file
84
web/src/views/develop/code/components/PreviewTab.vue
Normal file
@@ -0,0 +1,84 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-tabs type="line" animated>
|
||||
<n-tab-pane v-for="(view, index) in views" :key="index" :name="view.name" :tab="view.name">
|
||||
<n-tag :type="view.tag.type" class="tag-margin">
|
||||
{{ view.tag.label }}
|
||||
<template #icon>
|
||||
<n-icon :component="view.tag.icon" />
|
||||
</template>
|
||||
{{ view.path }}
|
||||
</n-tag>
|
||||
<n-scrollbar class="code-scrollbar" trigger="none">
|
||||
<n-code :code="view.content" />
|
||||
</n-scrollbar>
|
||||
</n-tab-pane>
|
||||
</n-tabs>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import {
|
||||
CheckmarkCircle,
|
||||
CheckmarkDoneCircle,
|
||||
CloseCircleOutline,
|
||||
HelpCircleOutline,
|
||||
RemoveCircleOutline,
|
||||
} from '@vicons/ionicons5';
|
||||
|
||||
interface Props {
|
||||
previewModel: any;
|
||||
showModal: boolean;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
previewModel: cloneDeep({ views: {} }),
|
||||
showModal: false,
|
||||
});
|
||||
|
||||
const views = computed(() => {
|
||||
let tmpViews: any = [];
|
||||
let i = 0;
|
||||
for (const [k, v] of Object.entries(props.previewModel.views)) {
|
||||
let item = v as any;
|
||||
item.name = k;
|
||||
switch (item.meth) {
|
||||
case 1:
|
||||
item.tag = { type: 'success', label: '创建文件', icon: CheckmarkCircle };
|
||||
break;
|
||||
case 2:
|
||||
item.tag = { type: 'warning', label: '覆盖文件', icon: CheckmarkDoneCircle };
|
||||
break;
|
||||
case 3:
|
||||
item.tag = { type: 'info', label: '已存在跳过', icon: CloseCircleOutline };
|
||||
break;
|
||||
case 4:
|
||||
item.tag = { type: 'error', label: '不生成', icon: RemoveCircleOutline };
|
||||
break;
|
||||
default:
|
||||
item.tag = { type: 'error', label: '未知状态', icon: HelpCircleOutline };
|
||||
}
|
||||
tmpViews[i] = item;
|
||||
i++;
|
||||
}
|
||||
return tmpViews;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
::v-deep(.alert-margin) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
::v-deep(.tag-margin) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
::v-deep(.code-scrollbar) {
|
||||
height: calc(100vh - 300px);
|
||||
background: #282b2e;
|
||||
color: #e0e2e4;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
62
web/src/views/develop/code/components/model.ts
Normal file
62
web/src/views/develop/code/components/model.ts
Normal file
@@ -0,0 +1,62 @@
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
export const genFileObj = {
|
||||
meth: 1,
|
||||
content: '',
|
||||
path: '',
|
||||
required: true,
|
||||
};
|
||||
|
||||
export interface joinAttr {
|
||||
uuid: string;
|
||||
linkTable: string;
|
||||
alias: string;
|
||||
linkMode: number;
|
||||
field: string;
|
||||
masterField: string;
|
||||
columns: any;
|
||||
}
|
||||
|
||||
export const genInfoObj = {
|
||||
id: 0,
|
||||
genType: 10,
|
||||
varName: '',
|
||||
options: {
|
||||
headOps: ['add', 'batchDel', 'export'],
|
||||
columnOps: ['edit', 'del', 'view', 'status', 'switch', 'check'],
|
||||
autoOps: ['genMenuPermissions', 'runDao', 'runService'],
|
||||
join: [],
|
||||
menu: {
|
||||
pid: 0,
|
||||
icon: 'MenuOutlined',
|
||||
sort: 0,
|
||||
},
|
||||
},
|
||||
dbName: '',
|
||||
tableName: '',
|
||||
tableComment: '',
|
||||
daoName: '',
|
||||
masterColumns: [],
|
||||
status: 2,
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
};
|
||||
|
||||
export const selectListObj = {
|
||||
db: [],
|
||||
genType: [],
|
||||
status: [],
|
||||
tables: [],
|
||||
formMode: [],
|
||||
formRole: [],
|
||||
dictMode: [],
|
||||
whereMode: [],
|
||||
buildMeth: [],
|
||||
};
|
||||
|
||||
export function newState(state) {
|
||||
if (state !== null) {
|
||||
return cloneDeep(state);
|
||||
}
|
||||
return cloneDeep(genInfoObj);
|
||||
}
|
||||
264
web/src/views/develop/code/deploy.vue
Normal file
264
web/src/views/develop/code/deploy.vue
Normal file
@@ -0,0 +1,264 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-spin :show="show" description="正在生成配置信息...">
|
||||
<n-card>
|
||||
<n-tabs
|
||||
type="card"
|
||||
class="card-tabs"
|
||||
:default-value="value"
|
||||
animated
|
||||
tab-style="min-width: 80px;"
|
||||
style="margin: 0 -4px"
|
||||
pane-style="padding-left: 4px; padding-right: 4px; box-sizing: border-box;"
|
||||
:on-update:value="updateTabs"
|
||||
ref="tabsRef"
|
||||
@close="handleClose"
|
||||
@add="handleAdd"
|
||||
>
|
||||
<n-tab-pane v-for="panel in panels" :key="panel" :name="panel">
|
||||
<template v-if="panel === '基本信息'">
|
||||
<BaseInfo v-model:value="genInfo" :selectList="selectList" />
|
||||
</template>
|
||||
|
||||
<template v-if="panel === '主表字段'">
|
||||
<EditMasterCell v-model:value="genInfo" :selectList="selectList" />
|
||||
</template>
|
||||
</n-tab-pane>
|
||||
|
||||
<n-tab-pane
|
||||
v-for="panel in slavePanels"
|
||||
:key="panel"
|
||||
:name="panel"
|
||||
v-show="slavePanels.length > 0 && slavePanels !== []"
|
||||
>
|
||||
<EditSlaveCell
|
||||
v-model:value="genInfo"
|
||||
:uuid="slaveMap[panel]"
|
||||
:selectList="selectList"
|
||||
/>
|
||||
</n-tab-pane>
|
||||
|
||||
<template #suffix>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="preview">预览代码</n-button>
|
||||
<n-button type="success" :loading="formBtnLoading" @click="submitBuild"
|
||||
>提交生成</n-button
|
||||
>
|
||||
<n-button type="info" dashed :loading="formBtnLoading" @click="submitSave"
|
||||
>仅保存配置</n-button
|
||||
>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-tabs>
|
||||
|
||||
<n-modal
|
||||
v-model:show="showModal"
|
||||
:block-scroll="false"
|
||||
:mask-closable="false"
|
||||
:show-icon="false"
|
||||
preset="card"
|
||||
title="预览代码"
|
||||
style="width: 95%"
|
||||
>
|
||||
<PreviewTab :previewModel="previewModel" />
|
||||
<template #action>
|
||||
<n-space justify="end">
|
||||
<n-button @click="() => (showModal = false)">关闭</n-button>
|
||||
<n-button type="info" :loading="formBtnLoading" @click="submitBuild"
|
||||
>提交生成</n-button
|
||||
>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-modal>
|
||||
</n-card>
|
||||
</n-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.card-tabs .n-tabs-nav--bar-type {
|
||||
padding-left: 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useDialog, useMessage } from 'naive-ui';
|
||||
import BaseInfo from './components/BaseInfo.vue';
|
||||
import EditMasterCell from './components/EditMasterCell.vue';
|
||||
import EditSlaveCell from './components/EditSlaveCell.vue';
|
||||
import { Selects, View, Preview, Build, Edit } from '@/api/develop/code';
|
||||
import { selectListObj, newState } from '@/views/develop/code/components/model';
|
||||
import PreviewTab from '@/views/develop/code/components/PreviewTab.vue';
|
||||
import { isJsonString } from '@/utils/is';
|
||||
|
||||
interface Props {
|
||||
genId?: number;
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), { genId: 0 });
|
||||
const router = useRouter();
|
||||
const genId = Number(router.currentRoute.value.params.id ?? props.genId);
|
||||
const show = ref(false);
|
||||
const message = useMessage();
|
||||
const selectList = ref<any>(selectListObj);
|
||||
const genInfo = ref(newState(null));
|
||||
const tabsRef = ref();
|
||||
const value = ref('基本信息');
|
||||
const panels = ref(['基本信息', '主表字段']);
|
||||
const slaveMap = ref<any>([]);
|
||||
const slavePanels = ref<any>([]);
|
||||
const showModal = ref(false);
|
||||
const formBtnLoading = ref(false);
|
||||
const previewModel = ref<any>();
|
||||
const dialog = useDialog();
|
||||
|
||||
onMounted(async () => {
|
||||
if (genId < 1 && props.genId < 1) {
|
||||
message.error('生成ID不正确,请检查!');
|
||||
return;
|
||||
}
|
||||
await getGenInfo();
|
||||
await loadSelect();
|
||||
});
|
||||
|
||||
async function getGenInfo() {
|
||||
let tmp = await View({ id: genId });
|
||||
if (isJsonString(tmp.options)) {
|
||||
tmp.options = JSON.parse(tmp.options);
|
||||
}
|
||||
|
||||
if (tmp.masterColumns === undefined || tmp.masterColumns.length === 0) {
|
||||
tmp.masterColumns = [];
|
||||
}
|
||||
if (isJsonString(tmp.masterColumns)) {
|
||||
tmp.masterColumns = JSON.parse(tmp.masterColumns);
|
||||
}
|
||||
|
||||
genInfo.value = tmp;
|
||||
}
|
||||
|
||||
watch(
|
||||
genInfo,
|
||||
(newVal, _oldVal) => {
|
||||
if (newVal.genType >= 10 && newVal.genType < 20) {
|
||||
handleAdd('主表字段');
|
||||
} else {
|
||||
handleClose('主表字段');
|
||||
}
|
||||
|
||||
if (newVal.options.join !== undefined) {
|
||||
slavePanels.value = [];
|
||||
for (let i = 0; i <= newVal.options.join.length; i++) {
|
||||
if (newVal.options.join[i]?.alias !== undefined && newVal.options.join[i]?.alias !== '') {
|
||||
handleSlaveAdd(
|
||||
'关联表[ ' + newVal.options.join[i]?.alias + ' ]',
|
||||
newVal.options.join[i]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true, // 是否深度监听
|
||||
}
|
||||
);
|
||||
|
||||
function updateTabs(value: string | number) {
|
||||
console.log('value:' + value);
|
||||
}
|
||||
|
||||
function handleAdd(name: string) {
|
||||
const nameIndex = panels.value.findIndex((panelName) => panelName === name);
|
||||
if (!~nameIndex) {
|
||||
panels.value.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
function handleSlaveAdd(name: string, join) {
|
||||
const nameIndex = slavePanels.value.findIndex((panelName) => panelName === name);
|
||||
if (!~nameIndex) {
|
||||
slavePanels.value.push(name);
|
||||
slaveMap.value[name] = join.uuid;
|
||||
}
|
||||
}
|
||||
|
||||
function _handleSlaveClose(name: string) {
|
||||
const nameIndex = panels.value.findIndex((panelName) => panelName === name);
|
||||
if (!~nameIndex) return;
|
||||
panels.value.splice(nameIndex, 1);
|
||||
if (name === value.value) {
|
||||
value.value = panels.value[Math.min(nameIndex, panels.value.length - 1)];
|
||||
}
|
||||
}
|
||||
|
||||
function handleClose(name: string) {
|
||||
const nameIndex = panels.value.findIndex((panelName) => panelName === name);
|
||||
if (!~nameIndex) return;
|
||||
panels.value.splice(nameIndex, 1);
|
||||
if (name === value.value) {
|
||||
value.value = panels.value[Math.min(nameIndex, panels.value.length - 1)];
|
||||
}
|
||||
}
|
||||
|
||||
const loadSelect = async () => {
|
||||
selectList.value = await Selects({});
|
||||
};
|
||||
|
||||
async function preview() {
|
||||
previewModel.value = await Preview(genInfo.value);
|
||||
showModal.value = true;
|
||||
}
|
||||
|
||||
function submitBuild() {
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要提交生成吗?',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Build(genInfo.value).then((_res) => {
|
||||
setTimeout(function () {
|
||||
location.reload();
|
||||
}, 1500);
|
||||
message.success('生成提交成功,即将刷新页面..');
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function submitSave() {
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要保存生成配置吗?',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Edit(genInfo.value).then((_res) => {
|
||||
message.success('操作成功');
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
::v-deep(.alert-margin) {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
::v-deep(.tag-margin) {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
::v-deep(.code-scrollbar) {
|
||||
height: calc(100vh - 300px);
|
||||
background: #282b2e;
|
||||
color: #e0e2e4;
|
||||
padding: 10px;
|
||||
}
|
||||
</style>
|
||||
@@ -1,39 +1,452 @@
|
||||
<template>
|
||||
<div class="flex flex-col justify-center page-container">
|
||||
<div class="text-center">
|
||||
<h1 class="text-base">代码生成,敬请期待</h1>
|
||||
<n-button type="info" @click="goHome">回到首页</n-button>
|
||||
</div>
|
||||
</div>
|
||||
<n-card :bordered="false" class="proCard">
|
||||
<n-card :bordered="false" title="代码生成"> 你可以在这里查看到平台所有的短信发送记录。 </n-card>
|
||||
<BasicForm @register="register" @submit="handleSubmit" @reset="handleReset" ref="searchFormRef">
|
||||
<template #statusSlot="{ model, field }">
|
||||
<n-input v-model:value="model[field]" />
|
||||
</template>
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
ref="actionRef"
|
||||
:actionColumn="actionColumn"
|
||||
@update:checked-row-keys="onCheckedRow"
|
||||
:scroll-x="1090"
|
||||
>
|
||||
<template #tableTitle>
|
||||
<n-button type="primary" @click="addTable">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<PlusOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
生成
|
||||
</n-button>
|
||||
|
||||
<n-button type="error" @click="batchDelete" :disabled="batchDeleteDisabled">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<DeleteOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
批量删除
|
||||
</n-button>
|
||||
</template>
|
||||
</BasicTable>
|
||||
|
||||
<n-modal
|
||||
v-model:show="showModal"
|
||||
:show-icon="false"
|
||||
preset="dialog"
|
||||
title="生成"
|
||||
:style="{
|
||||
width: dialogWidth,
|
||||
}"
|
||||
>
|
||||
<!-- <n-alert :show-icon="false" type="info">-->
|
||||
<!-- 注意:!-->
|
||||
<!-- </n-alert>-->
|
||||
<n-form
|
||||
:model="formParams"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
label-placement="left"
|
||||
:label-width="80"
|
||||
class="py-4"
|
||||
>
|
||||
<n-form-item label="生成类型" path="genType">
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="selectList.genType"
|
||||
v-model:value="formParams.genType"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item
|
||||
label="数据库"
|
||||
path="dbName"
|
||||
v-if="formParams.genType >= 10 && formParams.genType < 20"
|
||||
>
|
||||
<n-select
|
||||
placeholder="请选择"
|
||||
:options="selectList.db"
|
||||
v-model:value="formParams.dbName"
|
||||
@update:value="handleDbUpdateValue"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item
|
||||
label="数据库表"
|
||||
path="tableName"
|
||||
v-if="formParams.genType >= 10 && formParams.genType < 20"
|
||||
>
|
||||
<n-select
|
||||
filterable
|
||||
tag
|
||||
:loading="tablesLoading"
|
||||
placeholder="请选择"
|
||||
:options="selectList.tables"
|
||||
v-model:value="formParams.tableName"
|
||||
@update:value="handleTableUpdateValue"
|
||||
:disabled="formParams.dbName === ''"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item
|
||||
label="菜单名称"
|
||||
path="tableComment"
|
||||
v-show="formParams.genType >= 10 && formParams.genType < 20"
|
||||
>
|
||||
<n-input placeholder="请输入" v-model:value="formParams.tableComment" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="实体命名" path="varName">
|
||||
<n-input placeholder="请输入" v-model:value="formParams.varName" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
|
||||
<template #action>
|
||||
<n-space>
|
||||
<n-button @click="() => (showModal = false)">取消</n-button>
|
||||
<n-button type="info" :loading="formBtnLoading" @click="confirmForm">生成配置</n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-modal>
|
||||
</n-card>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { h, onBeforeMount, reactive, ref } from 'vue';
|
||||
import { NTag, TreeSelectOption, useDialog, useMessage } from 'naive-ui';
|
||||
import { BasicTable, TableAction } from '@/components/Table';
|
||||
import { BasicForm, FormSchema, useForm } from '@/components/Form/index';
|
||||
import { List, Delete, Edit, Selects, TableSelect } from '@/api/develop/code';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { PlusOutlined, DeleteOutlined } from '@vicons/antd';
|
||||
import { newState } from '@/views/develop/code/components/model';
|
||||
import { getOptionLabel } from '@/utils/hotgo';
|
||||
|
||||
const selectList = ref({
|
||||
db: [],
|
||||
genType: [],
|
||||
status: [],
|
||||
tables: [],
|
||||
formMode: [],
|
||||
formRole: [],
|
||||
dictMode: [],
|
||||
whereMode: [],
|
||||
});
|
||||
const columns = [
|
||||
{
|
||||
title: '生成ID',
|
||||
key: 'id',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '生成类型',
|
||||
key: 'genType',
|
||||
render(row) {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
type: 'info',
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => getOptionLabel(selectList.value.genType, row.genType),
|
||||
}
|
||||
);
|
||||
},
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: '实体命名',
|
||||
key: 'varName',
|
||||
render(row) {
|
||||
return row.varName;
|
||||
},
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '数据库',
|
||||
key: 'dbName',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: '数据表',
|
||||
key: 'tableName',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: '菜单名称',
|
||||
key: 'tableComment',
|
||||
width: 200,
|
||||
},
|
||||
{
|
||||
title: '生成状态',
|
||||
key: 'status',
|
||||
render(row) {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
type: row.status == 1 ? 'success' : 'warning',
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => getOptionLabel(selectList.value.status, row.status),
|
||||
}
|
||||
);
|
||||
},
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createdAt',
|
||||
width: 180,
|
||||
},
|
||||
{
|
||||
title: '更新时间',
|
||||
key: 'updatedAt',
|
||||
width: 180,
|
||||
},
|
||||
];
|
||||
|
||||
const dialog = useDialog();
|
||||
const batchDeleteDisabled = ref(true);
|
||||
const checkedIds = ref([]);
|
||||
const searchFormRef = ref<any>();
|
||||
|
||||
const schemas = ref<FormSchema[]>([
|
||||
{
|
||||
field: 'genType',
|
||||
component: 'NSelect',
|
||||
label: '生成类型',
|
||||
componentProps: {
|
||||
placeholder: '请选择生成类型',
|
||||
options: [],
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'varName',
|
||||
component: 'NInput',
|
||||
label: '实体命名',
|
||||
componentProps: {
|
||||
placeholder: '请输入实体命名',
|
||||
onInput: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
rules: [{ trigger: ['blur'] }],
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
component: 'NSelect',
|
||||
label: '生成状态',
|
||||
componentProps: {
|
||||
placeholder: '请选择状态码',
|
||||
options: [],
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
const router = useRouter();
|
||||
const showModal = ref(false);
|
||||
const formBtnLoading = ref(false);
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
const actionRef = ref();
|
||||
const formParams = ref<any>();
|
||||
|
||||
function goHome() {
|
||||
router.push('/');
|
||||
const rules = {
|
||||
varName: {
|
||||
required: true,
|
||||
trigger: ['blur', 'input'],
|
||||
message: '实体命名不能为空,首字母大写',
|
||||
},
|
||||
};
|
||||
|
||||
const actionColumn = reactive({
|
||||
width: 220,
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
// fixed: 'right',
|
||||
render(record) {
|
||||
return h(TableAction as any, {
|
||||
style: 'button',
|
||||
actions: [
|
||||
{
|
||||
label: '生成配置',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
onClick: handleDelete.bind(null, record),
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const [register, {}] = useForm({
|
||||
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
|
||||
labelWidth: 80,
|
||||
schemas,
|
||||
});
|
||||
|
||||
function onCheckedRow(rowKeys) {
|
||||
batchDeleteDisabled.value = rowKeys.length <= 0;
|
||||
checkedIds.value = rowKeys;
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record).then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function batchDelete() {
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete({ id: checkedIds.value }).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const loadDataTable = async (res) => {
|
||||
mapWidth();
|
||||
return await List({ ...res, ...searchFormRef.value?.formModel });
|
||||
};
|
||||
|
||||
function reloadTable() {
|
||||
actionRef.value.reload();
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
router.push({ name: 'develop_code_deploy', params: { id: record.id } });
|
||||
}
|
||||
|
||||
function handleSubmit(_values: Recordable) {
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
function handleReset(_values: Recordable) {
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
function addTable() {
|
||||
showModal.value = true;
|
||||
formParams.value = newState(null);
|
||||
}
|
||||
|
||||
function confirmForm(e) {
|
||||
e.preventDefault();
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('formParams:' + JSON.stringify(formParams.value));
|
||||
Edit(formParams.value).then((res) => {
|
||||
message.success('生成成功,正在前往配置');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
router.push({ name: 'develop_code_deploy', params: { id: res.id } });
|
||||
});
|
||||
});
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
formBtnLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
const dialogWidth = ref('50%');
|
||||
function mapWidth() {
|
||||
let val = document.body.clientWidth;
|
||||
const def = 840; // 默认宽度
|
||||
if (val < def) {
|
||||
dialogWidth.value = '100%';
|
||||
} else {
|
||||
dialogWidth.value = def + 'px';
|
||||
}
|
||||
|
||||
return dialogWidth.value;
|
||||
}
|
||||
|
||||
onBeforeMount(async () => {
|
||||
await loadSelect();
|
||||
});
|
||||
|
||||
const loadSelect = async () => {
|
||||
selectList.value = await Selects({});
|
||||
|
||||
for (const item of schemas.value) {
|
||||
switch (item.field) {
|
||||
case 'status':
|
||||
item.componentProps.options = selectList.value.status;
|
||||
break;
|
||||
case 'genType':
|
||||
item.componentProps.options = selectList.value.genType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const tablesLoading = ref(false);
|
||||
// 处理选项更新
|
||||
async function handleDbUpdateValue(
|
||||
value: string | number | Array<string | number> | null,
|
||||
_option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
) {
|
||||
tablesLoading.value = true;
|
||||
await loadTableSelect(value);
|
||||
tablesLoading.value = false;
|
||||
}
|
||||
|
||||
async function loadTableSelect(value) {
|
||||
selectList.value.tables = await TableSelect({ name: value });
|
||||
}
|
||||
|
||||
function handleTableUpdateValue(value, option) {
|
||||
formParams.value.varName = option?.defVarName as string;
|
||||
formParams.value.daoName = option?.daoName as string;
|
||||
formParams.value.tableComment = option?.defTableComment as string;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
.page-container {
|
||||
width: 100%;
|
||||
border-radius: 4px;
|
||||
padding: 50px 0;
|
||||
height: 60vh;
|
||||
|
||||
.text-center {
|
||||
h1 {
|
||||
color: #666;
|
||||
padding: 20px 0;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
width: 350px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<style lang="less" scoped></style>
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:openChecked="true"
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
@@ -223,7 +224,7 @@
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record)
|
||||
.then((_res) => {
|
||||
@@ -236,7 +237,7 @@
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -246,7 +247,7 @@
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete({ id: checkedIds.value })
|
||||
.then((_res) => {
|
||||
@@ -259,7 +260,7 @@
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:openChecked="true"
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
@@ -223,7 +224,7 @@
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record)
|
||||
.then((_res) => {
|
||||
@@ -236,7 +237,7 @@
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -246,7 +247,7 @@
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete({ id: checkedIds.value })
|
||||
.then((_res) => {
|
||||
@@ -259,7 +260,7 @@
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:openChecked="true"
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
@@ -169,7 +170,6 @@
|
||||
];
|
||||
|
||||
const router = useRouter();
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
const actionRef = ref();
|
||||
const formParams = ref({});
|
||||
@@ -218,25 +218,19 @@
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
console.log('点击了删除', record);
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
// message.error(e.message ?? '操作失败');
|
||||
});
|
||||
Delete(record).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -246,20 +240,15 @@
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete({ id: checkedIds.value })
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
});
|
||||
Delete({ id: checkedIds.value }).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -273,18 +262,15 @@
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
router.push({ name: 'log_view', params: { id: record.id } });
|
||||
}
|
||||
|
||||
function handleSubmit(values: Recordable) {
|
||||
console.log(values);
|
||||
formParams.value = values;
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
function handleReset(values: Recordable) {
|
||||
console.log(values);
|
||||
formParams.value = {};
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:openChecked="true"
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
@@ -223,7 +224,7 @@
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record)
|
||||
.then((_res) => {
|
||||
@@ -236,7 +237,7 @@
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -246,7 +247,7 @@
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete({ id: checkedIds.value })
|
||||
.then((_res) => {
|
||||
@@ -259,7 +260,7 @@
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:openChecked="true"
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
@@ -169,7 +170,6 @@
|
||||
];
|
||||
|
||||
const router = useRouter();
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
const actionRef = ref();
|
||||
const formParams = ref({});
|
||||
@@ -207,7 +207,6 @@
|
||||
});
|
||||
|
||||
function onCheckedRow(rowKeys) {
|
||||
console.log(rowKeys);
|
||||
if (rowKeys.length > 0) {
|
||||
batchDeleteDisabled.value = false;
|
||||
} else {
|
||||
@@ -218,25 +217,19 @@
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
console.log('点击了删除', record);
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
// message.error(e.message ?? '操作失败');
|
||||
});
|
||||
Delete(record).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -246,11 +239,10 @@
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete({ id: checkedIds.value })
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
@@ -259,7 +251,7 @@
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -273,12 +265,10 @@
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
router.push({ name: 'sms_view', params: { id: record.id } });
|
||||
}
|
||||
|
||||
function handleSubmit(values: Recordable) {
|
||||
console.log(values);
|
||||
formParams.value = values;
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
:rules="rules"
|
||||
>
|
||||
<n-form-item path="username">
|
||||
<n-input v-model:value="formInline.username" placeholder="请输入用户名">
|
||||
<n-input
|
||||
@keyup.enter="handleSubmit"
|
||||
v-model:value="formInline.username"
|
||||
placeholder="请输入用户名"
|
||||
>
|
||||
<template #prefix>
|
||||
<n-icon size="18" color="#808695">
|
||||
<PersonOutline />
|
||||
@@ -27,6 +31,7 @@
|
||||
</n-form-item>
|
||||
<n-form-item path="password">
|
||||
<n-input
|
||||
@keyup.enter="handleSubmit"
|
||||
v-model:value="formInline.password"
|
||||
type="password"
|
||||
showPasswordOn="click"
|
||||
@@ -140,8 +145,8 @@
|
||||
const toPath = decodeURIComponent((route.query?.redirect || '/') as string);
|
||||
message.success('登录成功,即将进入系统');
|
||||
if (route.name === LOGIN_NAME) {
|
||||
router.replace('/');
|
||||
} else router.replace(toPath);
|
||||
await router.replace('/');
|
||||
} else await router.replace(toPath);
|
||||
} else {
|
||||
message.info(msg || '登录失败');
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
import { BasicForm, FormSchema, useForm } from '@/components/Form/index';
|
||||
import { OnlineList, Offline } from '@/api/monitor/monitor';
|
||||
import { columns } from './columns';
|
||||
import { useRouter } from 'vue-router';
|
||||
|
||||
const dialog = useDialog();
|
||||
const schemas: FormSchema[] = [
|
||||
@@ -43,8 +42,6 @@
|
||||
},
|
||||
];
|
||||
|
||||
const router = useRouter();
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
const actionRef = ref();
|
||||
const formParams = ref({});
|
||||
@@ -62,10 +59,6 @@
|
||||
return h(TableAction as any, {
|
||||
style: 'button',
|
||||
actions: [
|
||||
// {
|
||||
// label: '查看详情',
|
||||
// onClick: handleEdit.bind(null, record),
|
||||
// },
|
||||
{
|
||||
label: '强制退出',
|
||||
onClick: handleDelete.bind(null, record),
|
||||
@@ -82,25 +75,19 @@
|
||||
});
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
console.log('点击了删除', record);
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要强制退出该用户?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Offline(record)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
// message.error(e.message ?? '操作失败');
|
||||
});
|
||||
Offline(record).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -113,19 +100,12 @@
|
||||
actionRef.value.reload();
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
router.push({ name: 'serve_log_view', params: { id: record.id } });
|
||||
}
|
||||
|
||||
function handleSubmit(values: Recordable) {
|
||||
console.log(values);
|
||||
formParams.value = values;
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
function handleReset(values: Recordable) {
|
||||
console.log(values);
|
||||
function handleReset(_values: Recordable) {
|
||||
formParams.value = {};
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:openChecked="true"
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
@@ -169,7 +170,6 @@
|
||||
];
|
||||
|
||||
const router = useRouter();
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
const actionRef = ref();
|
||||
const formParams = ref({});
|
||||
@@ -218,25 +218,19 @@
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
console.log('点击了删除', record);
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
// message.error(e.message ?? '操作失败');
|
||||
});
|
||||
Delete(record).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -246,20 +240,15 @@
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete({ id: checkedIds.value })
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
});
|
||||
Delete({ id: checkedIds.value }).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -273,18 +262,15 @@
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
router.push({ name: 'serve_log_view', params: { id: record.id } });
|
||||
}
|
||||
|
||||
function handleSubmit(values: Recordable) {
|
||||
console.log(values);
|
||||
formParams.value = values;
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
function handleReset(values: Recordable) {
|
||||
console.log(values);
|
||||
function handleReset(_values: Recordable) {
|
||||
formParams.value = {};
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<PlusOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
新建
|
||||
新建部门
|
||||
</n-button>
|
||||
</n-space>
|
||||
|
||||
@@ -30,11 +30,15 @@
|
||||
:row-key="rowKey"
|
||||
:loading="loading"
|
||||
default-expand-all
|
||||
|
||||
/>
|
||||
</n-space>
|
||||
|
||||
<n-modal v-model:show="showModal" :show-icon="false" preset="dialog" title="新建">
|
||||
<n-modal
|
||||
v-model:show="showModal"
|
||||
:show-icon="false"
|
||||
preset="dialog"
|
||||
:title="formParams?.id > 0 ? '编辑部门 #' + formParams?.id : '新建部门'"
|
||||
>
|
||||
<n-form
|
||||
:model="formParams"
|
||||
:rules="rules"
|
||||
@@ -111,6 +115,7 @@
|
||||
import { TableAction } from '@/components/Table';
|
||||
import { statusActions, statusOptions } from '@/enums/optionsiEnum';
|
||||
import { Delete, Edit, getDeptList, Status } from '@/api/org/dept';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
const rules = {
|
||||
name: {
|
||||
@@ -158,6 +163,8 @@
|
||||
schemas,
|
||||
});
|
||||
|
||||
const options = ref<any>([]);
|
||||
const optionsDefaultValue = ref<any>(null);
|
||||
const loading = ref(false);
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
@@ -165,7 +172,7 @@
|
||||
const showModal = ref(false);
|
||||
const formBtnLoading = ref(false);
|
||||
|
||||
let resetFormParams = {
|
||||
const defaultState = {
|
||||
id: 0,
|
||||
pid: 0,
|
||||
name: '',
|
||||
@@ -176,17 +183,14 @@
|
||||
email: '',
|
||||
sort: 0,
|
||||
status: 1,
|
||||
created_at: '',
|
||||
updated_at: '',
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
};
|
||||
let formParams = ref(resetFormParams);
|
||||
|
||||
const params = ref({
|
||||
pageSize: 5,
|
||||
name: 'xiaoMa',
|
||||
});
|
||||
let formParams = ref<any>();
|
||||
|
||||
type RowData = {
|
||||
createdAt: string;
|
||||
status: number;
|
||||
name: string;
|
||||
index: string;
|
||||
children?: RowData[];
|
||||
@@ -253,10 +257,10 @@
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'created_at',
|
||||
key: 'createdAt',
|
||||
width: 200,
|
||||
render: (rows, _) => {
|
||||
return rows.created_at; //timestampToTime();
|
||||
return rows.createdAt; //timestampToTime();
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -264,7 +268,7 @@
|
||||
key: 'actions',
|
||||
width: 220,
|
||||
// fixed: 'right',
|
||||
render(record) {
|
||||
render(record: any) {
|
||||
return h(TableAction as any, {
|
||||
style: 'button',
|
||||
actions: [
|
||||
@@ -279,9 +283,6 @@
|
||||
],
|
||||
dropDownActions: statusActions,
|
||||
select: (key) => {
|
||||
// console.log('select record:' + JSON.stringify(record));
|
||||
// message.info(`您点击了,${key} 按钮`);
|
||||
|
||||
updateStatus(record.id, key);
|
||||
},
|
||||
});
|
||||
@@ -293,13 +294,11 @@
|
||||
|
||||
function addTable() {
|
||||
showModal.value = true;
|
||||
formParams.value = resetFormParams;
|
||||
console.log('addTable formParams:' + JSON.stringify(formParams.value));
|
||||
formParams.value = cloneDeep(defaultState);
|
||||
optionsDefaultValue.value = null;
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
showModal.value = true;
|
||||
formParams.value = record;
|
||||
formParams.value.children = null;
|
||||
@@ -307,16 +306,14 @@
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
console.log('点击了删除', record);
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
loadDataTable({});
|
||||
})
|
||||
@@ -325,7 +322,7 @@
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -333,7 +330,6 @@
|
||||
function updateStatus(id, status) {
|
||||
Status({ id: id, status: status })
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
loadDataTable({});
|
||||
@@ -349,19 +345,13 @@
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('formParams:' + JSON.stringify(formParams.value));
|
||||
Edit(formParams.value)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
loadDataTable({});
|
||||
});
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
Edit(formParams.value).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
loadDataTable({});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
@@ -370,14 +360,11 @@
|
||||
}
|
||||
|
||||
async function handleSubmit(values: Recordable) {
|
||||
console.log('handleSubmit valuesL:' + JSON.stringify(values));
|
||||
// reloadTable();
|
||||
await loadDataTable(values);
|
||||
}
|
||||
|
||||
function handleReset(values: Recordable) {
|
||||
console.log(values);
|
||||
}
|
||||
function handleReset(_values: Recordable) {}
|
||||
|
||||
const loadDataTable = async (res) => {
|
||||
loading.value = true;
|
||||
@@ -404,14 +391,8 @@
|
||||
|
||||
function handleUpdateValue(
|
||||
value: string | number | Array<string | number> | null,
|
||||
option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
_option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
) {
|
||||
console.log(value, option);
|
||||
|
||||
formParams.value.pid = value;
|
||||
}
|
||||
|
||||
const options = ref([]);
|
||||
|
||||
const optionsDefaultValue = ref(null);
|
||||
</script>
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:openChecked="true"
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
@@ -29,7 +30,7 @@
|
||||
<PlusOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
新建
|
||||
新建岗位
|
||||
</n-button>
|
||||
|
||||
<n-button type="error" @click="batchDelete" :disabled="batchDeleteDisabled">
|
||||
@@ -43,7 +44,12 @@
|
||||
</template>
|
||||
</BasicTable>
|
||||
|
||||
<n-modal v-model:show="showModal" :show-icon="false" preset="dialog" title="新建">
|
||||
<n-modal
|
||||
v-model:show="showModal"
|
||||
:show-icon="false"
|
||||
preset="dialog"
|
||||
:title="formParams?.id > 0 ? '编辑岗位 #' + formParams?.id : '新建岗位'"
|
||||
>
|
||||
<n-form
|
||||
:model="formParams"
|
||||
:rules="rules"
|
||||
@@ -100,7 +106,7 @@
|
||||
import { DeleteOutlined, PlusOutlined } from '@vicons/antd';
|
||||
import { statusActions, statusOptions } from '@/enums/optionsiEnum';
|
||||
|
||||
const params = ref({
|
||||
const params = ref<any>({
|
||||
pageSize: 10,
|
||||
name: '',
|
||||
code: '',
|
||||
@@ -160,8 +166,8 @@
|
||||
const dialog = useDialog();
|
||||
const showModal = ref(false);
|
||||
const formBtnLoading = ref(false);
|
||||
const searchFormRef = ref({});
|
||||
const formRef = ref({});
|
||||
const searchFormRef = ref<any>({});
|
||||
const formRef = ref<any>({});
|
||||
const batchDeleteDisabled = ref(true);
|
||||
const checkedIds = ref([]);
|
||||
|
||||
@@ -179,7 +185,7 @@
|
||||
created_at: '',
|
||||
updated_at: '',
|
||||
};
|
||||
let formParams = ref(resetFormParams);
|
||||
let formParams = ref<any>(resetFormParams);
|
||||
|
||||
const actionColumn = reactive({
|
||||
width: 220,
|
||||
@@ -219,16 +225,12 @@
|
||||
}
|
||||
|
||||
const loadDataTable = async (res) => {
|
||||
return await getPostList({ ...params.value, ...res, ...searchFormRef.value.formModel });
|
||||
return await getPostList({ ...params.value, ...res, ...searchFormRef.value?.formModel });
|
||||
};
|
||||
|
||||
function onCheckedRow(rowKeys) {
|
||||
console.log(rowKeys);
|
||||
if (rowKeys.length > 0) {
|
||||
batchDeleteDisabled.value = false;
|
||||
} else {
|
||||
batchDeleteDisabled.value = true;
|
||||
}
|
||||
batchDeleteDisabled.value = rowKeys.length <= 0;
|
||||
|
||||
checkedIds.value = rowKeys;
|
||||
}
|
||||
@@ -242,10 +244,8 @@
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('formParams:' + JSON.stringify(formParams.value));
|
||||
Edit(formParams.value)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
@@ -264,31 +264,24 @@
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
showModal.value = true;
|
||||
formParams.value = record;
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
console.log('点击了删除', record);
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
// message.error(e.message ?? '操作失败');
|
||||
});
|
||||
Delete(record).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -298,7 +291,7 @@
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete({ id: checkedIds.value })
|
||||
.then((_res) => {
|
||||
@@ -311,7 +304,7 @@
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -328,17 +321,12 @@
|
||||
}
|
||||
|
||||
function updateStatus(id, status) {
|
||||
Status({ id: id, status: status })
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
reloadTable({});
|
||||
});
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
Status({ id: id, status: status }).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
reloadTable();
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ export const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'id',
|
||||
width: 50,
|
||||
width: 60,
|
||||
},
|
||||
{
|
||||
title: '用户名',
|
||||
@@ -14,7 +14,7 @@ export const columns = [
|
||||
},
|
||||
{
|
||||
title: '姓名',
|
||||
key: 'realname',
|
||||
key: 'realName',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
@@ -37,7 +37,7 @@ export const columns = [
|
||||
},
|
||||
{
|
||||
default: () =>
|
||||
row.realname !== '' ? row.realname.substring(0, 1) : row.username.substring(0, 2),
|
||||
row.realName !== '' ? row.realName.substring(0, 1) : row.username.substring(0, 2),
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -45,7 +45,7 @@ export const columns = [
|
||||
},
|
||||
{
|
||||
title: '绑定角色',
|
||||
key: 'role_name',
|
||||
key: 'roleName',
|
||||
width: 100,
|
||||
render(row) {
|
||||
return h(
|
||||
@@ -58,14 +58,14 @@ export const columns = [
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => row.role_name,
|
||||
default: () => row.roleName,
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '所属部门',
|
||||
key: 'dept_name',
|
||||
key: 'deptName',
|
||||
width: 100,
|
||||
render(row) {
|
||||
return h(
|
||||
@@ -78,7 +78,7 @@ export const columns = [
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => row.dept_name,
|
||||
default: () => row.deptName,
|
||||
}
|
||||
);
|
||||
},
|
||||
@@ -86,7 +86,7 @@ export const columns = [
|
||||
{
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
width: 50,
|
||||
width: 80,
|
||||
render(row) {
|
||||
return h(
|
||||
NTag,
|
||||
@@ -106,12 +106,12 @@ export const columns = [
|
||||
{
|
||||
title: '访问次数',
|
||||
key: 'visitCount',
|
||||
width: 80,
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createdAt',
|
||||
width: 100,
|
||||
width: 150,
|
||||
render: (rows, _) => {
|
||||
return rows.createdAt;
|
||||
},
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:openChecked="true"
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
@@ -23,13 +24,26 @@
|
||||
:scroll-x="1090"
|
||||
>
|
||||
<template #tableTitle>
|
||||
<n-button type="primary" @click="addTable">
|
||||
<n-button type="primary" @click="addTable" class="min-left-space">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<PlusOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
新建
|
||||
新建用户
|
||||
</n-button>
|
||||
<n-button
|
||||
type="error"
|
||||
@click="batchDelete"
|
||||
:disabled="batchDeleteDisabled"
|
||||
class="min-left-space"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<DeleteOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
批量删除
|
||||
</n-button>
|
||||
</template>
|
||||
</BasicTable>
|
||||
@@ -38,7 +52,7 @@
|
||||
v-model:show="showModal"
|
||||
:show-icon="false"
|
||||
preset="dialog"
|
||||
title="新建"
|
||||
:title="formParams?.id > 0 ? '编辑用户 #' + formParams?.id : '新建用户'"
|
||||
:style="{
|
||||
width: dialogWidth,
|
||||
}"
|
||||
@@ -53,12 +67,12 @@
|
||||
>
|
||||
<n-grid x-gap="24" :cols="2">
|
||||
<n-gi>
|
||||
<n-form-item label="姓名" path="realname">
|
||||
<n-input placeholder="请输入姓名" v-model:value="formParams.realname" />
|
||||
<n-form-item label="姓名" path="realName">
|
||||
<n-input placeholder="请输入姓名" v-model:value="formParams.realName" />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-form-item label="登录用户名" path="username">
|
||||
<n-form-item label="用户名" path="username">
|
||||
<n-input placeholder="请输入登录用户名" v-model:value="formParams.username" />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
@@ -66,19 +80,19 @@
|
||||
|
||||
<n-grid x-gap="24" :cols="2">
|
||||
<n-gi>
|
||||
<n-form-item label="绑定角色" path="role">
|
||||
<n-form-item label="绑定角色" path="roleId">
|
||||
<n-select
|
||||
:default-value="formParams.role"
|
||||
:default-value="formParams.roleId"
|
||||
:options="roleList"
|
||||
@update:value="handleUpdateRoleValue"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-form-item label="所属部门" path="dept_id">
|
||||
<n-form-item label="所属部门" path="deptId">
|
||||
<n-tree-select
|
||||
:options="deptList"
|
||||
:default-value="formParams.dept_id"
|
||||
:default-value="formParams.deptId"
|
||||
:default-expand-all="true"
|
||||
@update:value="handleUpdateDeptValue"
|
||||
/>
|
||||
@@ -169,15 +183,19 @@
|
||||
import { SelectOption, TreeSelectOption, useDialog, useMessage } from 'naive-ui';
|
||||
import { BasicTable, TableAction } from '@/components/Table';
|
||||
import { BasicForm, FormSchema, useForm } from '@/components/Form/index';
|
||||
import { Delete, Edit, List, Status } from '@/api/org/user';
|
||||
import { Delete, Edit, List, Status, ResetPwd } from '@/api/org/user';
|
||||
import { columns } from './columns';
|
||||
import { PlusOutlined } from '@vicons/antd';
|
||||
import { sexOptions, statusActions, statusOptions } from '@/enums/optionsiEnum';
|
||||
import { PlusOutlined, DeleteOutlined } from '@vicons/antd';
|
||||
import { sexOptions, statusOptions } from '@/enums/optionsiEnum';
|
||||
import { getDeptList } from '@/api/org/dept';
|
||||
import { getRoleList } from '@/api/system/role';
|
||||
import { getPostList } from '@/api/org/post';
|
||||
import { adaModalWidth } from '@/utils/hotgo';
|
||||
import { getRandomString } from '@/utils/charset';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { defRangeShortcuts } from '@/utils/dateUtil';
|
||||
|
||||
const params = ref({
|
||||
const params = ref<any>({
|
||||
pageSize: 10,
|
||||
name: '',
|
||||
code: '',
|
||||
@@ -185,10 +203,10 @@
|
||||
});
|
||||
|
||||
const rules = {
|
||||
name: {
|
||||
// required: true,
|
||||
username: {
|
||||
required: true,
|
||||
trigger: ['blur', 'input'],
|
||||
message: '请输入名称',
|
||||
message: '请输入用户名',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -206,7 +224,7 @@
|
||||
rules: [{ message: '请输入用户名', trigger: ['blur'] }],
|
||||
},
|
||||
{
|
||||
field: 'realname',
|
||||
field: 'realName',
|
||||
component: 'NInput',
|
||||
label: '姓名',
|
||||
componentProps: {
|
||||
@@ -220,7 +238,7 @@
|
||||
{
|
||||
field: 'mobile',
|
||||
component: 'NInputNumber',
|
||||
label: '手机',
|
||||
label: '手机号',
|
||||
componentProps: {
|
||||
placeholder: '请输入手机号码',
|
||||
showButton: false,
|
||||
@@ -229,6 +247,17 @@
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'email',
|
||||
component: 'NInput',
|
||||
label: '邮箱',
|
||||
componentProps: {
|
||||
placeholder: '请输入邮箱地址',
|
||||
onInput: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
component: 'NSelect',
|
||||
@@ -249,7 +278,7 @@
|
||||
componentProps: {
|
||||
type: 'datetimerange',
|
||||
clearable: true,
|
||||
// defaultValue: [new Date() - 86400000 * 30, new Date()],
|
||||
shortcuts: defRangeShortcuts(),
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
@@ -262,21 +291,21 @@
|
||||
const dialog = useDialog();
|
||||
const showModal = ref(false);
|
||||
const formBtnLoading = ref(false);
|
||||
const searchFormRef = ref({});
|
||||
const formRef = ref({});
|
||||
const searchFormRef = ref<any>({});
|
||||
const formRef = ref<any>({});
|
||||
const batchDeleteDisabled = ref(true);
|
||||
const checkedIds = ref([]);
|
||||
const deptList = ref([]);
|
||||
const roleList = ref([]);
|
||||
const postList = ref([]);
|
||||
|
||||
const resetFormParams = {
|
||||
const deptList = ref<any>([]);
|
||||
const roleList = ref<any>([]);
|
||||
const postList = ref<any>([]);
|
||||
const dialogWidth = ref('50%');
|
||||
const defaultState = {
|
||||
id: 0,
|
||||
role: null,
|
||||
realname: '',
|
||||
roleId: null,
|
||||
realName: '',
|
||||
username: '',
|
||||
password: '',
|
||||
dept_id: null,
|
||||
deptId: null,
|
||||
postIds: null,
|
||||
mobile: '',
|
||||
email: '',
|
||||
@@ -285,10 +314,11 @@
|
||||
phone: '',
|
||||
sort: 0,
|
||||
status: 1,
|
||||
created_at: '',
|
||||
updated_at: '',
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
};
|
||||
let formParams = ref(resetFormParams);
|
||||
|
||||
let formParams = ref<any>();
|
||||
|
||||
const actionColumn = reactive({
|
||||
width: 220,
|
||||
@@ -308,9 +338,27 @@
|
||||
onClick: handleDelete.bind(null, record),
|
||||
},
|
||||
],
|
||||
dropDownActions: statusActions,
|
||||
dropDownActions: [
|
||||
{
|
||||
label: '重置密码',
|
||||
key: 0,
|
||||
},
|
||||
{
|
||||
label: '设为启用',
|
||||
key: 1,
|
||||
},
|
||||
{
|
||||
label: '设为禁用',
|
||||
key: 2,
|
||||
},
|
||||
],
|
||||
select: (key) => {
|
||||
updateStatus(record.id, key);
|
||||
if (key === 0) {
|
||||
return handleResetPwd(record);
|
||||
}
|
||||
if (key === 1 || key === 2) {
|
||||
return updateStatus(record.id, key);
|
||||
}
|
||||
},
|
||||
});
|
||||
},
|
||||
@@ -324,18 +372,18 @@
|
||||
|
||||
function addTable() {
|
||||
showModal.value = true;
|
||||
formParams.value = resetFormParams;
|
||||
formParams.value = cloneDeep(defaultState);
|
||||
}
|
||||
|
||||
const loadDataTable = async (res) => {
|
||||
mapWidth();
|
||||
adaModalWidth(dialogWidth);
|
||||
deptList.value = await getDeptList({});
|
||||
if (deptList.value === undefined || deptList.value === null) {
|
||||
deptList.value = [];
|
||||
}
|
||||
|
||||
roleList.value = [];
|
||||
let roleLists = await getRoleList();
|
||||
let roleLists = await getRoleList({ pageSize: 100 });
|
||||
if (roleLists.list === undefined || roleLists.list === null) {
|
||||
roleLists = [];
|
||||
} else {
|
||||
@@ -363,19 +411,12 @@
|
||||
postList.value[i].value = postLists[i].id;
|
||||
}
|
||||
}
|
||||
console.log('post.value:' + JSON.stringify(postList.value));
|
||||
|
||||
return await List({ ...params.value, ...res, ...searchFormRef.value.formModel });
|
||||
return await List({ ...params.value, ...res, ...searchFormRef.value?.formModel });
|
||||
};
|
||||
|
||||
function onCheckedRow(rowKeys) {
|
||||
console.log(rowKeys);
|
||||
if (rowKeys.length > 0) {
|
||||
batchDeleteDisabled.value = false;
|
||||
} else {
|
||||
batchDeleteDisabled.value = true;
|
||||
}
|
||||
|
||||
batchDeleteDisabled.value = rowKeys.length <= 0;
|
||||
checkedIds.value = rowKeys;
|
||||
}
|
||||
|
||||
@@ -388,20 +429,13 @@
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('formParams:' + JSON.stringify(formParams.value));
|
||||
Edit(formParams.value)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
reloadTable();
|
||||
formParams.value = ref(resetFormParams);
|
||||
});
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
// message.error(e.message ?? '操作失败');
|
||||
Edit(formParams.value).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
reloadTable();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
@@ -410,31 +444,61 @@
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
showModal.value = true;
|
||||
formParams.value = record;
|
||||
formParams.value = cloneDeep(record);
|
||||
}
|
||||
|
||||
function handleResetPwd(record: Recordable) {
|
||||
record.password = getRandomString(12);
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要重置密码?\r\n重置成功后密码为:' + record.password + '\r\n 请先保存',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
ResetPwd(record).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
console.log('点击了删除', record);
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((_e: Error) => {
|
||||
// message.error(_e.message ?? '操作失败');
|
||||
});
|
||||
Delete(record).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function batchDelete() {
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete({ id: checkedIds.value }).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -451,57 +515,32 @@
|
||||
}
|
||||
|
||||
function updateStatus(id, status) {
|
||||
Status({ id: id, status: status })
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
reloadTable();
|
||||
});
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
Status({ id: id, status: status }).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
reloadTable();
|
||||
});
|
||||
}
|
||||
|
||||
const dialogWidth = ref('50%');
|
||||
|
||||
function mapWidth() {
|
||||
let val = document.body.clientWidth;
|
||||
const def = 720; // 默认宽度
|
||||
if (val < def) {
|
||||
dialogWidth.value = '100%';
|
||||
} else {
|
||||
dialogWidth.value = def + 'px';
|
||||
}
|
||||
|
||||
return dialogWidth.value;
|
||||
});
|
||||
}
|
||||
|
||||
function handleUpdateDeptValue(
|
||||
value: string | number | Array<string | number> | null,
|
||||
option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
_option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
) {
|
||||
console.log(value, option);
|
||||
|
||||
formParams.value.dept_id = value;
|
||||
formParams.value.deptId = value;
|
||||
}
|
||||
|
||||
function handleUpdateRoleValue(
|
||||
value: string | number | Array<string | number> | null,
|
||||
option: SelectOption | null | Array<SelectOption | null>
|
||||
_option: SelectOption | null | Array<SelectOption | null>
|
||||
) {
|
||||
console.log(value, option);
|
||||
|
||||
formParams.value.role = value;
|
||||
formParams.value.roleId = value;
|
||||
}
|
||||
|
||||
function handleUpdatePostValue(
|
||||
value: string | number | Array<string | number> | null,
|
||||
option: SelectOption | null | Array<SelectOption | null>
|
||||
_option: SelectOption | null | Array<SelectOption | null>
|
||||
) {
|
||||
console.log(value, option);
|
||||
|
||||
formParams.value.postIds = value;
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<n-drawer v-model:show="isDrawer" :width="width" :placement="placement">
|
||||
<n-drawer v-model:show="isDrawer" :width="width" :placement="placement" :mask-closable="false">
|
||||
<n-drawer-content :title="title" closable>
|
||||
<n-form
|
||||
:model="formParams"
|
||||
@@ -19,12 +19,7 @@
|
||||
/>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
<n-form-item
|
||||
:label="
|
||||
formParams.type === 1 ? '上级目录' : formParams.type === 2 ? '上级菜单' : '上级按钮'
|
||||
"
|
||||
path="pid"
|
||||
>
|
||||
<n-form-item label="上级目录" path="pid">
|
||||
<n-tree-select
|
||||
:options="optionTreeData"
|
||||
default-value="0"
|
||||
@@ -37,102 +32,85 @@
|
||||
"
|
||||
path="title"
|
||||
>
|
||||
<n-input
|
||||
:placeholder="
|
||||
formParams.type === 1 ? '目录名称' : formParams.type === 2 ? '菜单名称' : '按钮名称'
|
||||
"
|
||||
v-model:value="formParams.title"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="" path="icon">
|
||||
<div style="width: 120px">
|
||||
<span>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
请填写图标编码,可以参考图标库,也可以不填使用默认图标
|
||||
</n-tooltip>
|
||||
<span> 图标 </span>
|
||||
</span>
|
||||
</div>
|
||||
<n-input placeholder="图标映射路径" v-model:value="formParams.icon" />
|
||||
</n-form-item>
|
||||
<n-form-item label="" path="path">
|
||||
<div style="width: 120px">
|
||||
<span>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
路由地址,如:user
|
||||
</n-tooltip>
|
||||
<span> 路由地址 </span>
|
||||
</span>
|
||||
</div>
|
||||
<n-input placeholder="路由地址" v-model:value="formParams.path" />
|
||||
</n-form-item>
|
||||
<n-form-item label="" path="name">
|
||||
<div style="width: 120px">
|
||||
<span>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
对应路由配置文件中 `name` 只能是唯一性,配置 `http(s)://` 开头地址 则会新窗口打开
|
||||
</n-tooltip>
|
||||
<span> 路由别名 </span>
|
||||
</span>
|
||||
</div>
|
||||
<n-input placeholder="路由别名" v-model:value="formParams.name" />
|
||||
</n-form-item>
|
||||
<n-form-item label="" path="component">
|
||||
<div style="width: 120px">
|
||||
<span>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
访问的组件路径,如:`/system/menu/menu`,默认在`views`目录下,默认 `LAYOUT`
|
||||
如果是多级菜单 `ParentLayout`
|
||||
</n-tooltip>
|
||||
<span> 组件路径 </span>
|
||||
</span>
|
||||
</div>
|
||||
<n-input placeholder="组件路径" v-model:value="formParams.component" />
|
||||
</n-form-item>
|
||||
<n-form-item label="" path="redirect" v-show="formParams.type === 1">
|
||||
<div style="width: 120px">
|
||||
<span>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
默认跳转路由地址,如:`/system/menu/menu` 多级路由情况下适用
|
||||
</n-tooltip>
|
||||
<span> 默认跳转 </span>
|
||||
</span>
|
||||
</div>
|
||||
<n-input placeholder="默认路由跳转地址" v-model:value="formParams.redirect" />
|
||||
</n-form-item>
|
||||
<n-divider title-placement="left">功能设置</n-divider>
|
||||
<n-form-item label="API权限" path="permissions">
|
||||
<n-input
|
||||
placeholder="请输入API权限,多个权限用,分割"
|
||||
v-model:value="formParams.permissions"
|
||||
/>
|
||||
</n-form-item>
|
||||
<!-- <n-form-item label="权限名称" path="permissionName">-->
|
||||
<!-- <n-input placeholder="权限名称" v-model:value="formParams.permissionName" />-->
|
||||
<!-- </n-form-item>-->
|
||||
<n-form-item label="高亮路由" path="activeMenu">
|
||||
<n-input placeholder="高亮路由" v-model:value="formParams.activeMenu" />
|
||||
</n-form-item>
|
||||
<n-form-item label="排序" path="sort">
|
||||
<n-input-number v-model:value="formParams.sort" clearable />
|
||||
<n-input placeholder="请输入" v-model:value="formParams.title" />
|
||||
</n-form-item>
|
||||
|
||||
<n-grid x-gap="24" :cols="2">
|
||||
<n-form-item path="icon" v-if="formParams.type !== 3">
|
||||
<IconSelector style="width: 100%" v-model:value="formParams.icon" option="antd" />
|
||||
<template #label>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
请填写图标编码,可以参考图标库,也可以不填使用默认图标
|
||||
</n-tooltip>
|
||||
菜单图标</template
|
||||
>
|
||||
</n-form-item>
|
||||
<n-form-item path="path" v-if="formParams.type !== 3">
|
||||
<n-input placeholder="路由地址" v-model:value="formParams.path" />
|
||||
<template #label>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
请路由地址,如:user
|
||||
</n-tooltip>
|
||||
路由地址</template
|
||||
>
|
||||
</n-form-item>
|
||||
<n-form-item path="name">
|
||||
<n-input placeholder="路由别名" v-model:value="formParams.name" />
|
||||
<template #label>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
对应路由配置文件中 `name` 只能是唯一性,配置 `http(s)://` 开头地址 则会新窗口打开
|
||||
</n-tooltip>
|
||||
路由别名</template
|
||||
>
|
||||
</n-form-item>
|
||||
<n-form-item label="组件路径" path="component" v-if="formParams.type !== 3">
|
||||
<n-input placeholder="组件路径" v-model:value="formParams.component" />
|
||||
<template #feedback>
|
||||
主目录填 `LAYOUT`;多级父目录填
|
||||
`ParentLayout`;页面填具体的组件路径,如:`/system/menu/menu`</template
|
||||
>
|
||||
</n-form-item>
|
||||
<n-form-item label="默认跳转" path="redirect" v-if="formParams.type === 1">
|
||||
<n-input placeholder="默认路由跳转地址" v-model:value="formParams.redirect" />
|
||||
<template #feedback
|
||||
>默认跳转路由地址,如:`/system/menu/menu` 多级路由情况下适用</template
|
||||
>
|
||||
</n-form-item>
|
||||
<n-divider title-placement="left">功能设置</n-divider>
|
||||
<n-form-item label="分配权限" path="permissions">
|
||||
<n-input
|
||||
placeholder="请输入分配权限,多个权限用,分割"
|
||||
v-model:value="formParams.permissions"
|
||||
/>
|
||||
<template #label>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
请填写API路由地址,可同时作用于服务端和web端。多个权限用,分割
|
||||
</n-tooltip>
|
||||
分配权限</template
|
||||
>
|
||||
</n-form-item>
|
||||
<!-- <n-form-item label="权限名称" path="permissionName">-->
|
||||
<!-- <n-input placeholder="权限名称" v-model:value="formParams.permissionName" />-->
|
||||
<!-- </n-form-item>-->
|
||||
<n-form-item label="高亮路由" path="activeMenu" v-if="formParams.type !== 3">
|
||||
<n-input placeholder="高亮路由" v-model:value="formParams.activeMenu" />
|
||||
</n-form-item>
|
||||
<n-form-item label="菜单排序" path="sort">
|
||||
<n-input-number style="width: 100%" v-model:value="formParams.sort" clearable />
|
||||
</n-form-item>
|
||||
|
||||
<n-grid x-gap="24" :cols="2" v-if="formParams.type !== 3">
|
||||
<n-gi>
|
||||
<n-form-item label="根路由" path="isRoot">
|
||||
<n-radio-group v-model:value="formParams.isRoot" name="isRoot">
|
||||
@@ -159,7 +137,7 @@
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<n-grid x-gap="24" :cols="2">
|
||||
<n-grid x-gap="24" :cols="2" v-if="formParams.type !== 3">
|
||||
<n-gi>
|
||||
<n-form-item label="缓存路由" path="keepAlive">
|
||||
<n-radio-group v-model:value="formParams.keepAlive" name="keepAlive">
|
||||
@@ -186,7 +164,7 @@
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<n-grid x-gap="24" :cols="2">
|
||||
<n-grid x-gap="24" :cols="2" v-if="formParams.type !== 3">
|
||||
<n-gi>
|
||||
<n-form-item label="是否外链" path="isFrame">
|
||||
<n-radio-group v-model:value="formParams.isFrame" name="isFrame">
|
||||
@@ -200,33 +178,29 @@
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-form-item label="状态" path="status">
|
||||
<n-radio-group v-model:value="formParams.status" name="status">
|
||||
<n-radio-button
|
||||
v-for="status in statusMap"
|
||||
:key="status.value"
|
||||
:value="status.value"
|
||||
:label="status.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
<n-form-item label="外部地址" path="frameSrc" v-show="formParams.isFrame === 1">
|
||||
<n-input placeholder="内联外部地址" v-model:value="formParams.frameSrc" />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<n-grid x-gap="24" :cols="2">
|
||||
<n-gi>
|
||||
<n-form-item label="外部地址" path="frameSrc" v-show="formParams.isFrame === true">
|
||||
<n-input placeholder="内联外部地址" v-model:value="formParams.frameSrc" />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi />
|
||||
</n-grid>
|
||||
<n-form-item label="状态" path="status">
|
||||
<n-radio-group v-model:value="formParams.status" name="status">
|
||||
<n-radio-button
|
||||
v-for="status in statusMap"
|
||||
:key="status.value"
|
||||
:value="status.value"
|
||||
:label="status.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
|
||||
<template #footer>
|
||||
<n-space>
|
||||
<n-button type="primary" :loading="subLoading" @click="formSubmit">提交</n-button>
|
||||
<n-button type="primary" :loading="subLoading" @click="formSubmit">确认添加</n-button>
|
||||
<n-button @click="handleReset">重置</n-button>
|
||||
<n-button @click="closeDrawer">取消</n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-drawer-content>
|
||||
@@ -235,9 +209,10 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, ref, toRefs } from 'vue';
|
||||
import { TreeSelectOption, useMessage } from 'naive-ui';
|
||||
import { FormItemRule, TreeSelectOption, useMessage } from 'naive-ui';
|
||||
import { QuestionCircleOutlined } from '@vicons/antd';
|
||||
import { EditMenu } from '@/api/system/menu';
|
||||
import { newState } from '@/views/permission/menu/model';
|
||||
|
||||
const menuTypes = [
|
||||
{
|
||||
@@ -295,18 +270,6 @@
|
||||
return s;
|
||||
});
|
||||
|
||||
const rules = {
|
||||
label: {
|
||||
required: true,
|
||||
message: '请输入标题',
|
||||
trigger: 'blur',
|
||||
},
|
||||
path: {
|
||||
required: true,
|
||||
message: '请输入路径',
|
||||
trigger: 'blur',
|
||||
},
|
||||
};
|
||||
export default defineComponent({
|
||||
name: 'CreateDrawer',
|
||||
components: {},
|
||||
@@ -316,8 +279,7 @@
|
||||
default: '添加顶级菜单',
|
||||
},
|
||||
optionTreeData: {
|
||||
type: Object,
|
||||
// eslint-disable-next-line vue/require-valid-default-prop
|
||||
type: Object || Array,
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
@@ -325,47 +287,42 @@
|
||||
setup(_props, context) {
|
||||
const message = useMessage();
|
||||
const formRef: any = ref(null);
|
||||
const defaultValueRef = () => ({
|
||||
id: 0,
|
||||
pid: 0,
|
||||
title: '',
|
||||
name: '',
|
||||
path: '',
|
||||
label: '',
|
||||
icon: '',
|
||||
type: 1,
|
||||
redirect: '',
|
||||
permissions: '',
|
||||
permissionName: '',
|
||||
component: '',
|
||||
alwaysShow: 1,
|
||||
activeMenu: '',
|
||||
isRoot: 0,
|
||||
isFrame: 0,
|
||||
frameSrc: '',
|
||||
keepAlive: 0,
|
||||
hidden: 0,
|
||||
affix: 0,
|
||||
status: 1,
|
||||
sort: 10,
|
||||
});
|
||||
|
||||
const state = reactive({
|
||||
const state = reactive<any>({
|
||||
width: 700,
|
||||
isDrawer: false,
|
||||
subLoading: false,
|
||||
formParams: defaultValueRef(),
|
||||
formParams: newState(null),
|
||||
placement: 'right',
|
||||
icon: '',
|
||||
alertText:
|
||||
'该功能主要实时预览各种布局效果,更多完整配置在 projectSetting.ts 中设置,建议在生产环境关闭该布局预览功能。',
|
||||
});
|
||||
const rules = {
|
||||
title: {
|
||||
required: true,
|
||||
message: '请输入名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
label: {
|
||||
required: true,
|
||||
message: '请输入标题',
|
||||
trigger: 'blur',
|
||||
},
|
||||
path: {
|
||||
required: false,
|
||||
message: '请输入路由地址',
|
||||
trigger: 'blur',
|
||||
validator: function (_rule: FormItemRule, value: any, callback: Function) {
|
||||
if (state.formParams.type != 3 && !value) {
|
||||
callback(new Error('请输入路由地址'));
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
function openDrawer() {
|
||||
if (document.body.clientWidth < 700) {
|
||||
state.width = document.body.clientWidth;
|
||||
}
|
||||
state.isDrawer = true;
|
||||
state.formParams = newState(null);
|
||||
}
|
||||
|
||||
function closeDrawer() {
|
||||
@@ -375,17 +332,17 @@
|
||||
function formSubmit() {
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('state.formParams:' + JSON.stringify(state.formParams));
|
||||
state.subLoading = true;
|
||||
EditMenu({ ...state.formParams })
|
||||
.then(async (_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
state.subLoading = false;
|
||||
message.success('操作成功');
|
||||
handleReset();
|
||||
await context.emit('loadData');
|
||||
closeDrawer();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
.catch((_e: Error) => {
|
||||
state.subLoading = false;
|
||||
});
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
@@ -395,15 +352,14 @@
|
||||
|
||||
function handleReset() {
|
||||
formRef.value.restoreValidation();
|
||||
state.formParams = Object.assign(state.formParams, defaultValueRef());
|
||||
state.formParams = newState(null);
|
||||
}
|
||||
|
||||
// 处理选项更新
|
||||
function handleUpdateValue(
|
||||
value: string | number | Array<string | number> | null,
|
||||
option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
_option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
) {
|
||||
console.log(value, option);
|
||||
state.formParams.pid = value;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +1,16 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="n-layout-page-header">
|
||||
<n-card :bordered="false" title="菜单管理"> 在这里可以管理编辑系统下的所有菜单导航</n-card>
|
||||
<n-card :bordered="false" title="菜单管理">
|
||||
在这里可以管理编辑系统下的所有菜单导航和分配相应的菜单权限</n-card
|
||||
>
|
||||
</div>
|
||||
<n-grid class="mt-4" cols="1 s:1 m:1 l:3 xl:3 2xl:3" responsive="screen" :x-gap="12">
|
||||
<n-gi span="1">
|
||||
<n-card :segmented="{ content: true }" :bordered="false" size="small">
|
||||
<template #header>
|
||||
<n-space>
|
||||
<!-- <n-dropdown trigger="hover" @select="selectAddMenu" :options="addMenuOptions">-->
|
||||
<!-- <n-button type="info" ghost icon-placement="right">-->
|
||||
<!-- 添加菜单-->
|
||||
<!-- <template #icon>-->
|
||||
<!-- <div class="flex items-center">-->
|
||||
<!-- <n-icon size="14">-->
|
||||
<!-- <DownOutlined />-->
|
||||
<!-- </n-icon>-->
|
||||
<!-- </div>-->
|
||||
<!-- </template>-->
|
||||
<!-- </n-button>-->
|
||||
<!-- </n-dropdown>-->
|
||||
|
||||
<n-button type="info" ghost icon-placement="left" @click="openCreateDrawer">
|
||||
<n-button type="info" icon-placement="left" @click="openCreateDrawer">
|
||||
<template #icon>
|
||||
<div class="flex items-center">
|
||||
<n-icon size="14">
|
||||
@@ -31,7 +20,7 @@
|
||||
</template>
|
||||
添加菜单
|
||||
</n-button>
|
||||
<n-button type="info" ghost icon-placement="left" @click="packHandle">
|
||||
<n-button type="primary" icon-placement="left" @click="packHandle">
|
||||
全部{{ expandedKeys.length ? '收起' : '展开' }}
|
||||
<template #icon>
|
||||
<div class="flex items-center">
|
||||
@@ -88,7 +77,6 @@
|
||||
}}</span>
|
||||
</n-space>
|
||||
</template>
|
||||
<!-- <n-alert type="info" closable> 从菜单列表选择一项后,进行编辑</n-alert>-->
|
||||
<n-form
|
||||
:model="formParams"
|
||||
:rules="rules"
|
||||
@@ -100,7 +88,7 @@
|
||||
>
|
||||
<n-divider title-placement="left">基本设置</n-divider>
|
||||
|
||||
<n-grid x-gap="24" :cols="2">
|
||||
<n-grid cols="2 300:1 600:2">
|
||||
<n-gi>
|
||||
<n-form-item label="类型" path="type">
|
||||
<n-radio-group v-model:value="formParams.type" name="type">
|
||||
@@ -114,16 +102,7 @@
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-form-item
|
||||
:label="
|
||||
formParams.type === 1
|
||||
? '上级目录'
|
||||
: formParams.type === 2
|
||||
? '上级菜单'
|
||||
: '上级按钮'
|
||||
"
|
||||
path="pid"
|
||||
>
|
||||
<n-form-item label="上级目录" path="pid">
|
||||
<n-tree-select
|
||||
:options="optionTreeData"
|
||||
:value="formParams.pid"
|
||||
@@ -133,7 +112,7 @@
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<n-grid x-gap="24" :cols="2">
|
||||
<n-grid cols="2 300:1 600:2">
|
||||
<n-gi>
|
||||
<n-form-item
|
||||
:label="
|
||||
@@ -145,132 +124,119 @@
|
||||
"
|
||||
path="title"
|
||||
>
|
||||
<n-input
|
||||
:placeholder="
|
||||
formParams.type === 1
|
||||
? '目录名称'
|
||||
: formParams.type === 2
|
||||
? '菜单名称'
|
||||
: '按钮名称'
|
||||
"
|
||||
v-model:value="formParams.title"
|
||||
/>
|
||||
<n-input placeholder="请输入" v-model:value="formParams.title" />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-form-item label="" path="icon">
|
||||
<div style="width: 120px">
|
||||
<span>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
请填写图标编码,可以参考图标库,也可以不填使用默认图标
|
||||
</n-tooltip>
|
||||
<span> 图标 </span>
|
||||
</span>
|
||||
</div>
|
||||
<n-input placeholder="图标映射路径" v-model:value="formParams.icon" />
|
||||
<n-gi v-if="formParams.type !== 3">
|
||||
<n-form-item path="icon">
|
||||
<IconSelector style="width: 100%" v-model:value="formParams.icon" option="antd" />
|
||||
<template #label>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
请填写图标编码,可以参考图标库,也可以不填使用默认图标
|
||||
</n-tooltip>
|
||||
菜单图标</template
|
||||
>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<n-grid x-gap="24" :cols="2">
|
||||
<n-gi>
|
||||
<n-form-item label="" path="path">
|
||||
<div style="width: 120px">
|
||||
<span>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
路由地址,如:user
|
||||
</n-tooltip>
|
||||
<span> 路由地址 </span>
|
||||
</span>
|
||||
</div>
|
||||
<n-grid cols="2 300:1 600:2">
|
||||
<n-gi v-if="formParams.type !== 3">
|
||||
<n-form-item path="path">
|
||||
<n-input placeholder="路由地址" v-model:value="formParams.path" />
|
||||
<template #label>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
请路由地址,如:user
|
||||
</n-tooltip>
|
||||
路由地址</template
|
||||
>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-form-item label="" path="name">
|
||||
<div style="width: 120px">
|
||||
<span>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
对应路由配置文件中 `name` 只能是唯一性,配置 `http(s)://` 开头地址
|
||||
则会新窗口打开
|
||||
</n-tooltip>
|
||||
<span> 路由别名 </span>
|
||||
</span>
|
||||
</div>
|
||||
<n-form-item path="name">
|
||||
<n-input placeholder="路由别名" v-model:value="formParams.name" />
|
||||
<template #label>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
对应路由配置文件中 `name` 只能是唯一性,配置 `http(s)://` 开头地址
|
||||
则会新窗口打开
|
||||
</n-tooltip>
|
||||
路由别名</template
|
||||
>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<n-grid x-gap="24" :cols="2">
|
||||
<n-grid cols="2 300:1 600:2" v-if="formParams.type !== 3">
|
||||
<n-gi>
|
||||
<n-form-item label="" path="component">
|
||||
<div style="width: 120px">
|
||||
<span>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
访问的组件路径,如:`/system/menu/menu`,默认在`views`目录下,默认 `LAYOUT`
|
||||
如果是多级菜单 `ParentLayout`
|
||||
</n-tooltip>
|
||||
<span> 组件路径 </span>
|
||||
</span>
|
||||
</div>
|
||||
<n-form-item label="组件路径" path="component">
|
||||
<n-input placeholder="组件路径" v-model:value="formParams.component" />
|
||||
<template #feedback>
|
||||
主目录填 `LAYOUT`;多级父目录填
|
||||
`ParentLayout`;页面填具体的组件路径,如:`/system/menu/menu`</template
|
||||
>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-form-item label="" path="redirect">
|
||||
<div style="width: 120px">
|
||||
<span>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
默认跳转路由地址,如:`/system/menu/menu` 多级路由情况下适用
|
||||
</n-tooltip>
|
||||
<span> 默认跳转 </span>
|
||||
</span>
|
||||
</div>
|
||||
<n-gi v-if="formParams.type === 1">
|
||||
<n-form-item label="默认跳转" path="redirect">
|
||||
<n-input placeholder="默认路由跳转地址" v-model:value="formParams.redirect" />
|
||||
<template #feedback
|
||||
>默认跳转路由地址,如:`/system/menu/menu` 多级路由情况下适用</template
|
||||
>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<n-divider title-placement="left">功能设置</n-divider>
|
||||
<n-form-item label="排序" path="sort">
|
||||
<n-input-number v-model:value="formParams.sort" clearable />
|
||||
</n-form-item>
|
||||
<n-grid x-gap="24" :cols="2">
|
||||
|
||||
<n-grid cols="1 ">
|
||||
<n-gi>
|
||||
<n-form-item label="API权限" path="permissions">
|
||||
<n-form-item label="分配权限" path="permissions">
|
||||
<n-input
|
||||
placeholder="请输入API权限,多个权限用,分割"
|
||||
placeholder="请输入分配权限,多个权限用,分割"
|
||||
v-model:value="formParams.permissions"
|
||||
/>
|
||||
<template #label>
|
||||
<n-tooltip trigger="hover">
|
||||
<template #trigger>
|
||||
<n-icon :component="QuestionCircleOutlined" :size="18" :depth="3" />
|
||||
</template>
|
||||
请填写API路由地址,可同时作用于服务端和web端。多个权限用,分割
|
||||
</n-tooltip>
|
||||
分配权限</template
|
||||
>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<!-- <n-form-item label="权限名称" path="permissionName">-->
|
||||
<!-- <n-input placeholder="权限名称" v-model:value="formParams.permissionName" />-->
|
||||
<!-- </n-form-item>-->
|
||||
<!-- <n-gi>-->
|
||||
<!-- <n-form-item label="权限名称" path="permissionName">-->
|
||||
<!-- <n-input placeholder="权限名称" v-model:value="formParams.permissionName" />-->
|
||||
<!-- <template #feedback>分配权限存在多个时,权限名称只绑定到第一个权限</template>-->
|
||||
<!-- </n-form-item>-->
|
||||
<!-- </n-gi>-->
|
||||
</n-grid>
|
||||
|
||||
<n-grid cols="2 300:1 600:2">
|
||||
<n-gi v-if="formParams.type !== 3">
|
||||
<n-form-item label="高亮路由" path="activeMenu">
|
||||
<n-input placeholder="高亮路由" v-model:value="formParams.activeMenu" />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-form-item label="菜单排序" path="sort">
|
||||
<n-input-number style="width: 100%" v-model:value="formParams.sort" clearable />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<n-grid x-gap="24" :cols="4">
|
||||
<n-grid cols="4 300:1 400:2 600:3 800:4" v-if="formParams.type !== 3">
|
||||
<n-gi>
|
||||
<n-form-item label="根路由" path="isRoot">
|
||||
<n-radio-group v-model:value="formParams.isRoot" name="isRoot">
|
||||
@@ -321,19 +287,7 @@
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
|
||||
<n-grid x-gap="24" :cols="4">
|
||||
<n-gi>
|
||||
<n-form-item label="是否外链" path="isFrame">
|
||||
<n-radio-group v-model:value="formParams.isFrame" name="isFrame">
|
||||
<n-radio-button
|
||||
v-for="switchStatus in switchStatusMap"
|
||||
:key="switchStatus.value"
|
||||
:value="switchStatus.value"
|
||||
:label="switchStatus.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-grid cols="4 300:1 400:2 600:3 800:4">
|
||||
<n-gi>
|
||||
<n-form-item label="状态" path="status">
|
||||
<n-radio-group v-model:value="formParams.status" name="status">
|
||||
@@ -346,8 +300,20 @@
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<n-form-item label="外部地址" path="frameSrc" v-show="formParams.isFrame === true">
|
||||
<n-gi v-if="formParams.type !== 3">
|
||||
<n-form-item label="是否外链" path="isFrame">
|
||||
<n-radio-group v-model:value="formParams.isFrame" name="isFrame">
|
||||
<n-radio-button
|
||||
v-for="switchStatus in switchStatusMap"
|
||||
:key="switchStatus.value"
|
||||
:value="switchStatus.value"
|
||||
:label="switchStatus.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
<n-gi v-if="formParams.type !== 3">
|
||||
<n-form-item label="外部地址" path="frameSrc" v-show="formParams.isFrame === 1">
|
||||
<n-input placeholder="内联外部地址" v-model:value="formParams.frameSrc" />
|
||||
</n-form-item>
|
||||
</n-gi>
|
||||
@@ -376,7 +342,7 @@
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, reactive, ref, unref } from 'vue';
|
||||
import { TreeSelectOption, useDialog, useMessage } from 'naive-ui';
|
||||
import { FormItemRule, TreeSelectOption, useDialog, useMessage } from 'naive-ui';
|
||||
import {
|
||||
AlignLeftOutlined,
|
||||
FormOutlined,
|
||||
@@ -387,6 +353,9 @@
|
||||
import { DeleteMenu, EditMenu, getMenuList } from '@/api/system/menu';
|
||||
import { getTreeItem } from '@/utils';
|
||||
import CreateDrawer from './CreateDrawer.vue';
|
||||
import IconSelector from '@/components/IconSelector/index.vue';
|
||||
import { State, newState } from '@/views/permission/menu/model';
|
||||
import { validate } from '@/utils/validateUtil';
|
||||
|
||||
const menuTypes = [
|
||||
{
|
||||
@@ -407,7 +376,7 @@
|
||||
|
||||
const switchStatusMap = [
|
||||
{
|
||||
value: 0,
|
||||
value: 2,
|
||||
label: '关闭',
|
||||
},
|
||||
{
|
||||
@@ -445,15 +414,25 @@
|
||||
});
|
||||
|
||||
const rules = {
|
||||
title: {
|
||||
required: true,
|
||||
message: '请输入名称',
|
||||
trigger: 'blur',
|
||||
},
|
||||
label: {
|
||||
required: true,
|
||||
message: '请输入标题',
|
||||
trigger: 'blur',
|
||||
},
|
||||
path: {
|
||||
required: true,
|
||||
message: '请输入路径',
|
||||
required: false,
|
||||
message: '请输入路由地址',
|
||||
trigger: 'blur',
|
||||
validator: function (_rule: FormItemRule, value: any, callback: Function) {
|
||||
if (formParams.type != 3 && !value) {
|
||||
callback(new Error('请输入路由地址'));
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -470,41 +449,9 @@
|
||||
const treeItemTitle = ref('');
|
||||
const pattern = ref('');
|
||||
const drawerTitle = ref('');
|
||||
const optionTreeData = ref([
|
||||
{
|
||||
id: 0,
|
||||
key: 0,
|
||||
label: '根目录',
|
||||
pid: 0,
|
||||
title: '根目录',
|
||||
type: 1,
|
||||
},
|
||||
]);
|
||||
const optionTreeData = ref<any>([]);
|
||||
|
||||
const formParams = reactive({
|
||||
id: 0,
|
||||
pid: 0,
|
||||
title: '',
|
||||
name: '',
|
||||
path: '',
|
||||
label: '',
|
||||
icon: '',
|
||||
type: 1,
|
||||
redirect: '',
|
||||
permissions: '',
|
||||
permissionName: '',
|
||||
component: '',
|
||||
alwaysShow: 1,
|
||||
activeMenu: '',
|
||||
isRoot: 0,
|
||||
isFrame: 0,
|
||||
frameSrc: '',
|
||||
keepAlive: 0,
|
||||
hidden: 0,
|
||||
affix: 0,
|
||||
status: 1,
|
||||
sort: 10,
|
||||
});
|
||||
const formParams = reactive<State>(newState(null));
|
||||
|
||||
function openCreateDrawer() {
|
||||
drawerTitle.value = '添加菜单';
|
||||
@@ -527,23 +474,16 @@
|
||||
}
|
||||
|
||||
function handleDel() {
|
||||
dialog.info({
|
||||
dialog.warning({
|
||||
title: '提示',
|
||||
content: `您确定想删除此权限吗?`,
|
||||
content: `您确定要删除此菜单吗?`,
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
console.log('DeleteMenu formParams:' + JSON.stringify(formParams));
|
||||
DeleteMenu({ ...formParams })
|
||||
.then(async (_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
// handleReset();
|
||||
await loadData();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
});
|
||||
DeleteMenu({ ...formParams }).then(async (_res) => {
|
||||
message.success('操作成功');
|
||||
await loadData();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
message.error('已取消');
|
||||
@@ -559,17 +499,15 @@
|
||||
function formSubmit() {
|
||||
formRef.value.validate((errors: boolean) => {
|
||||
if (!errors) {
|
||||
console.log('formParams:' + JSON.stringify(formParams));
|
||||
// message.error('抱歉,您没有该权限');
|
||||
subLoading.value = true;
|
||||
EditMenu({ ...formParams })
|
||||
.then(async (_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
subLoading.value = false;
|
||||
message.success('操作成功');
|
||||
// handleReset();
|
||||
await loadData();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
.catch((_e: Error) => {
|
||||
subLoading.value = false;
|
||||
});
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
@@ -588,10 +526,9 @@
|
||||
// 处理选项更新
|
||||
function handleUpdateValue(
|
||||
value: string | number | Array<string | number> | null,
|
||||
option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
_option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
) {
|
||||
formParams.pid = value;
|
||||
console.log(value, option);
|
||||
formParams.pid = value as number;
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
@@ -603,8 +540,17 @@
|
||||
const keys = treeMenuList.list.map((item) => item.key);
|
||||
Object.assign(formParams, keys);
|
||||
treeData.value = [];
|
||||
optionTreeData.value = [];
|
||||
treeData.value = treeMenuList.list;
|
||||
optionTreeData.value = [
|
||||
{
|
||||
id: 0,
|
||||
key: 0,
|
||||
label: '根目录',
|
||||
pid: 0,
|
||||
title: '根目录',
|
||||
type: 1,
|
||||
},
|
||||
];
|
||||
optionTreeData.value = optionTreeData.value.concat(treeMenuList.list);
|
||||
loading.value = false;
|
||||
}
|
||||
@@ -612,8 +558,4 @@
|
||||
function onExpandedKeys(keys) {
|
||||
expandedKeys.value = keys;
|
||||
}
|
||||
|
||||
const editConfirm = (val) => {
|
||||
console.log(val);
|
||||
};
|
||||
</script>
|
||||
|
||||
58
web/src/views/permission/menu/model.ts
Normal file
58
web/src/views/permission/menu/model.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
|
||||
export interface State {
|
||||
id: number;
|
||||
pid: number;
|
||||
title: string;
|
||||
name: string;
|
||||
path: string;
|
||||
label: string;
|
||||
icon: string;
|
||||
type: number;
|
||||
redirect: string;
|
||||
permissions: string;
|
||||
permissionName: string;
|
||||
component: string;
|
||||
alwaysShow: number;
|
||||
activeMenu: string;
|
||||
isRoot: number;
|
||||
isFrame: number;
|
||||
frameSrc: string;
|
||||
keepAlive: number;
|
||||
hidden: number;
|
||||
affix: number;
|
||||
status: number;
|
||||
sort: number;
|
||||
}
|
||||
|
||||
export const defaultState = {
|
||||
id: 0,
|
||||
pid: 0,
|
||||
title: '',
|
||||
name: '',
|
||||
path: '',
|
||||
label: '',
|
||||
icon: '',
|
||||
type: 1,
|
||||
redirect: '',
|
||||
permissions: '',
|
||||
permissionName: '',
|
||||
component: '',
|
||||
alwaysShow: 1,
|
||||
activeMenu: '',
|
||||
isRoot: 0,
|
||||
isFrame: 2,
|
||||
frameSrc: '',
|
||||
keepAlive: 0,
|
||||
hidden: 0,
|
||||
affix: 0,
|
||||
status: 1,
|
||||
sort: 10,
|
||||
};
|
||||
|
||||
export function newState(state: State | null): State {
|
||||
if (state !== null) {
|
||||
return cloneDeep(state);
|
||||
}
|
||||
return cloneDeep(defaultState);
|
||||
}
|
||||
@@ -3,16 +3,27 @@ import { NTag } from 'naive-ui';
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
title: 'id',
|
||||
title: '角色ID',
|
||||
key: 'id',
|
||||
},
|
||||
{
|
||||
title: '角色名称',
|
||||
key: 'name',
|
||||
render(row) {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
type: 'info',
|
||||
},
|
||||
{
|
||||
default: () => row.name,
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '说明',
|
||||
key: 'remark',
|
||||
title: '上级角色',
|
||||
key: 'pid',
|
||||
},
|
||||
{
|
||||
title: '是否默认角色',
|
||||
@@ -29,6 +40,14 @@ export const columns = [
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '排序',
|
||||
key: 'sort',
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
key: 'remark',
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createdAt',
|
||||
|
||||
@@ -67,6 +67,9 @@
|
||||
:label-width="80"
|
||||
class="py-4"
|
||||
>
|
||||
<n-form-item label="上级角色" path="pid">
|
||||
<n-input placeholder="请输入上级角色ID" v-model:value="formParams.pid" />
|
||||
</n-form-item>
|
||||
<n-form-item label="角色名称" path="name">
|
||||
<n-input placeholder="请输入名称" v-model:value="formParams.name" />
|
||||
</n-form-item>
|
||||
@@ -99,23 +102,71 @@
|
||||
</n-space>
|
||||
</template>
|
||||
</n-modal>
|
||||
|
||||
<n-modal
|
||||
v-model:show="showDataModal"
|
||||
:show-icon="false"
|
||||
preset="dialog"
|
||||
:title="'修改 ' + dataForm?.name + ' 的数据权限'"
|
||||
>
|
||||
<n-form
|
||||
:model="dataForm"
|
||||
ref="dataFormRef"
|
||||
label-placement="left"
|
||||
:label-width="120"
|
||||
class="py-4"
|
||||
>
|
||||
<n-form-item label="数据范围" path="dataScope">
|
||||
<n-select
|
||||
v-model:value="dataForm.dataScope"
|
||||
:options="dataScopeOption"
|
||||
@update:value="handleUpdateDataScopeValue"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="自定义权限" path="customDept" v-if="dataForm.dataScope === 4">
|
||||
<n-tree-select
|
||||
multiple
|
||||
:options="deptList"
|
||||
:default-value="dataForm.customDept"
|
||||
:default-expand-all="true"
|
||||
@update:value="handleUpdateDeptValue"
|
||||
/>
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
|
||||
<template #action>
|
||||
<n-space>
|
||||
<n-button @click="() => (showDataModal = false)">取消</n-button>
|
||||
<n-button type="info" :loading="dataFormBtnLoading" @click="confirmDataForm"
|
||||
>确定</n-button
|
||||
>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { h, onMounted, reactive, ref, unref } from 'vue';
|
||||
import { useDialog, useMessage } from 'naive-ui';
|
||||
import { h, onMounted, reactive, ref } from 'vue';
|
||||
import { TreeSelectOption, useDialog, useMessage, SelectOption } from 'naive-ui';
|
||||
import { BasicTable, TableAction } from '@/components/Table';
|
||||
import { Delete, Edit, GetPermissions, getRoleList, UpdatePermissions } from '@/api/system/role';
|
||||
import {
|
||||
Delete,
|
||||
Edit,
|
||||
GetPermissions,
|
||||
getRoleList,
|
||||
UpdatePermissions,
|
||||
DataScopeSelect,
|
||||
DataScopeEdit,
|
||||
} from '@/api/system/role';
|
||||
import { getMenuList } from '@/api/system/menu';
|
||||
import { columns } from './columns';
|
||||
import { PlusOutlined } from '@vicons/antd';
|
||||
import { getTreeAll } from '@/utils';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { statusOptions } from '@/enums/optionsiEnum';
|
||||
import { copyObj } from '@/utils/array';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { getDeptList } from '@/api/org/dept';
|
||||
|
||||
const router = useRouter();
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
const actionRef = ref();
|
||||
@@ -124,13 +175,12 @@
|
||||
const showModal = ref(false);
|
||||
const formBtnLoading = ref(false);
|
||||
const formBtnLoading2 = ref(false);
|
||||
const checkedAll = ref(false);
|
||||
const checkedAll = ref<any>(false);
|
||||
const editRoleTitle = ref('');
|
||||
const treeData = ref([]);
|
||||
const expandedKeys = ref([]);
|
||||
const checkedKeys = ref([]);
|
||||
|
||||
const updatePermissionsParams = ref({});
|
||||
const checkedKeys = ref<any>([]);
|
||||
const updatePermissionsParams = ref<any>({});
|
||||
|
||||
const rules = {
|
||||
name: {
|
||||
@@ -138,54 +188,51 @@
|
||||
trigger: ['blur', 'input'],
|
||||
message: '请输入名称',
|
||||
},
|
||||
address: {
|
||||
key: {
|
||||
required: true,
|
||||
trigger: ['blur', 'input'],
|
||||
message: '请输入地址',
|
||||
},
|
||||
date: {
|
||||
type: 'number',
|
||||
required: true,
|
||||
trigger: ['blur', 'change'],
|
||||
message: '请选择日期',
|
||||
message: '请输入角色编码',
|
||||
},
|
||||
};
|
||||
let formParams = reactive({
|
||||
|
||||
const defaultState = {
|
||||
id: 0,
|
||||
pid: 0,
|
||||
level: 1,
|
||||
tree: '',
|
||||
name: '',
|
||||
key: '',
|
||||
remark: null,
|
||||
status: 1,
|
||||
sort: 0,
|
||||
dataScope: 0,
|
||||
deptCheckStrictly: 0,
|
||||
menuCheckStrictly: 0,
|
||||
});
|
||||
dataScope: 1,
|
||||
customDept: [],
|
||||
};
|
||||
|
||||
const params = reactive({
|
||||
pageSize: 5,
|
||||
name: 'xiaoMa',
|
||||
});
|
||||
let formParams = ref<any>(cloneDeep(defaultState));
|
||||
|
||||
const actionColumn = reactive({
|
||||
width: 250,
|
||||
width: 320,
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
fixed: 'right',
|
||||
render(record) {
|
||||
return h(TableAction, {
|
||||
style: 'button',
|
||||
style: 'primary',
|
||||
actions: [
|
||||
{
|
||||
label: '菜单权限',
|
||||
onClick: handleMenuAuth.bind(null, record),
|
||||
// 根据业务控制是否显示 isShow 和 auth 是并且关系
|
||||
ifShow: () => {
|
||||
// console.log('ifShow record:'+JSON.stringify(record))
|
||||
return record.key !== 'super';
|
||||
},
|
||||
// 根据权限控制是否显示: 有权限,会显示,支持多个
|
||||
// auth: ['basic_list'],
|
||||
},
|
||||
{
|
||||
label: '数据权限',
|
||||
onClick: handleDataAuth.bind(null, record),
|
||||
ifShow: () => {
|
||||
return record.key !== 'super';
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '编辑',
|
||||
@@ -193,18 +240,13 @@
|
||||
ifShow: () => {
|
||||
return record.key !== 'super';
|
||||
},
|
||||
// auth: ['basic_list'],
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
// icon: 'ic:outline-delete-outline',
|
||||
onClick: handleDelete.bind(null, record),
|
||||
// 根据业务控制是否显示 isShow 和 auth 是并且关系
|
||||
ifShow: () => {
|
||||
return record.key !== 'super';
|
||||
},
|
||||
// 根据权限控制是否显示: 有权限,会显示,支持多个
|
||||
// auth: ['basic_list'],
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -212,11 +254,7 @@
|
||||
});
|
||||
|
||||
const loadDataTable = async (res: any) => {
|
||||
let _params = {
|
||||
...unref(params),
|
||||
...res,
|
||||
};
|
||||
return await getRoleList(_params);
|
||||
return await getRoleList({ ...res });
|
||||
};
|
||||
|
||||
function onCheckedRow(rowKeys: any[]) {
|
||||
@@ -228,8 +266,6 @@
|
||||
}
|
||||
|
||||
function confirmForm(e: any) {
|
||||
console.log('checkedKeys.value:' + JSON.stringify(checkedKeys.value));
|
||||
console.log('updatePermissionsParams.value:' + JSON.stringify(updatePermissionsParams.value));
|
||||
e.preventDefault();
|
||||
formBtnLoading.value = true;
|
||||
UpdatePermissions({
|
||||
@@ -238,17 +274,12 @@
|
||||
menuIds:
|
||||
checkedKeys.value === undefined || checkedKeys.value == null ? [] : checkedKeys.value,
|
||||
},
|
||||
})
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
showModal.value = false;
|
||||
formBtnLoading.value = false;
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
});
|
||||
}).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
showModal.value = false;
|
||||
formBtnLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function confirmForm2(e) {
|
||||
@@ -256,19 +287,13 @@
|
||||
formBtnLoading2.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('formParams:' + JSON.stringify(formParams));
|
||||
Edit(formParams)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal2.value = false;
|
||||
reloadTable();
|
||||
});
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
Edit(formParams.value).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal2.value = false;
|
||||
reloadTable();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
@@ -278,34 +303,28 @@
|
||||
|
||||
function addTable() {
|
||||
showModal2.value = true;
|
||||
formParams.value = cloneDeep(defaultState);
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
showModal2.value = true;
|
||||
formParams = copyObj(formParams, record);
|
||||
formParams.value = cloneDeep(record);
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
console.log('点击了删除', record);
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
});
|
||||
Delete(record).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -313,12 +332,51 @@
|
||||
async function handleMenuAuth(record: Recordable) {
|
||||
editRoleTitle.value = `分配 ${record.name} 的菜单权限`;
|
||||
const data = await GetPermissions({ ...{ id: record.id } });
|
||||
console.log('data:' + JSON.stringify(data));
|
||||
checkedKeys.value = data.menuIds; //record.menu_keys;
|
||||
updatePermissionsParams.value.id = record.id;
|
||||
showModal.value = true;
|
||||
}
|
||||
|
||||
const dataScopeOption = ref<any>();
|
||||
const deptList = ref<any>([]);
|
||||
const dataFormRef = ref<any>();
|
||||
const dataFormBtnLoading = ref(false);
|
||||
const showDataModal = ref(false);
|
||||
const dataForm = ref<any>();
|
||||
function handleDataAuth(record: Recordable) {
|
||||
dataForm.value = cloneDeep(record);
|
||||
showDataModal.value = true;
|
||||
}
|
||||
|
||||
function handleUpdateDataScopeValue(value: string, option: SelectOption) {}
|
||||
|
||||
function handleUpdateDeptValue(
|
||||
value: string | number | Array<string | number> | null,
|
||||
_option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
) {
|
||||
dataForm.value.customDept = value;
|
||||
}
|
||||
|
||||
function confirmDataForm(e) {
|
||||
e.preventDefault();
|
||||
dataFormBtnLoading.value = true;
|
||||
dataFormRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('dataForm.value:' + JSON.stringify(dataForm.value));
|
||||
DataScopeEdit(dataForm.value).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showDataModal.value = false;
|
||||
reloadTable();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
dataFormBtnLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function checkedTree(keys) {
|
||||
checkedKeys.value = keys;
|
||||
}
|
||||
@@ -346,10 +404,28 @@
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await loadMenuList();
|
||||
await loadDeptList();
|
||||
await loadDataScopeSelect();
|
||||
});
|
||||
|
||||
async function loadMenuList() {
|
||||
const treeMenuList = await getMenuList();
|
||||
expandedKeys.value = treeMenuList.list.map((item) => item.key);
|
||||
treeData.value = treeMenuList.list;
|
||||
});
|
||||
}
|
||||
|
||||
async function loadDeptList() {
|
||||
deptList.value = await getDeptList({});
|
||||
if (deptList.value === undefined || deptList.value === null) {
|
||||
deptList.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDataScopeSelect() {
|
||||
const option = await DataScopeSelect();
|
||||
dataScopeOption.value = option.list;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, ref, toRefs } from 'vue';
|
||||
import { useDialog, useMessage } from 'naive-ui';
|
||||
import { useMessage } from 'naive-ui';
|
||||
|
||||
const rules = {
|
||||
name: {
|
||||
@@ -156,8 +156,6 @@
|
||||
setup() {
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
const dialog = useDialog();
|
||||
|
||||
const state = reactive({
|
||||
formValue: {
|
||||
bigWidth: '',
|
||||
@@ -171,23 +169,6 @@
|
||||
},
|
||||
});
|
||||
|
||||
function systemOpenChange(value) {
|
||||
if (!value) {
|
||||
dialog.warning({
|
||||
title: '提示',
|
||||
content: '您确定要关闭系统访问吗?该操作立马生效,请慎重操作!',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
message.success('操作成功');
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
state.formValue.systemOpen = true;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function formSubmit() {
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
@@ -211,7 +192,6 @@
|
||||
rules,
|
||||
formSubmit,
|
||||
resetForm,
|
||||
systemOpenChange,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
import { h } from 'vue';
|
||||
import { NTag } from 'naive-ui';
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'id',
|
||||
},
|
||||
{
|
||||
title: 'IP地址',
|
||||
key: 'ip',
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
key: 'remark',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
render(row) {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
type: row.status == 1 ? 'success' : 'warning',
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => (row.status == 1 ? '正常' : '隐藏'),
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createdAt',
|
||||
},
|
||||
];
|
||||
@@ -14,6 +14,7 @@
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:openChecked="true"
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
@@ -96,16 +97,60 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { h, reactive, ref } from 'vue';
|
||||
import { useDialog, useMessage } from 'naive-ui';
|
||||
import { h, onMounted, reactive, ref } from 'vue';
|
||||
import { NTag, useDialog, useMessage } from 'naive-ui';
|
||||
import { BasicTable, TableAction } from '@/components/Table';
|
||||
import { BasicForm, FormSchema, useForm } from '@/components/Form/index';
|
||||
import { Delete, Edit, List, Status } from '@/api/sys/blacklist';
|
||||
import { columns } from './columns';
|
||||
import { DeleteOutlined, PlusOutlined } from '@vicons/antd';
|
||||
import { statusActions, statusOptions } from '@/enums/optionsiEnum';
|
||||
import { Dict } from '@/api/dict/dict';
|
||||
import { getOptionLabel, getOptionTag } from '@/utils/hotgo';
|
||||
|
||||
const params = ref({
|
||||
const options = ref({
|
||||
status: [],
|
||||
});
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'id',
|
||||
},
|
||||
{
|
||||
title: 'IP地址',
|
||||
key: 'ip',
|
||||
},
|
||||
{
|
||||
title: '备注',
|
||||
key: 'remark',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
render(row) {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
type: getOptionTag(options.value.status, row.status),
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => getOptionLabel(options.value.status, row.status),
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createdAt',
|
||||
},
|
||||
];
|
||||
|
||||
const params = ref<any>({
|
||||
pageSize: 10,
|
||||
title: '',
|
||||
content: '',
|
||||
@@ -120,7 +165,7 @@
|
||||
},
|
||||
};
|
||||
|
||||
const schemas: FormSchema[] = [
|
||||
const schemas = ref<FormSchema[]>([
|
||||
{
|
||||
field: 'ip',
|
||||
component: 'NInput',
|
||||
@@ -140,21 +185,21 @@
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
placeholder: '请选择类型',
|
||||
options: statusOptions,
|
||||
options: [],
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
]);
|
||||
|
||||
const message = useMessage();
|
||||
const actionRef = ref();
|
||||
const dialog = useDialog();
|
||||
const showModal = ref(false);
|
||||
const formBtnLoading = ref(false);
|
||||
const searchFormRef = ref({});
|
||||
const formRef = ref({});
|
||||
const searchFormRef = ref<any>({});
|
||||
const formRef = ref<any>({});
|
||||
const batchDeleteDisabled = ref(true);
|
||||
const checkedIds = ref([]);
|
||||
|
||||
@@ -165,7 +210,7 @@
|
||||
sort: 0,
|
||||
status: 1,
|
||||
};
|
||||
let formParams = ref(resetFormParams);
|
||||
let formParams = ref<any>(resetFormParams);
|
||||
|
||||
const actionColumn = reactive({
|
||||
width: 220,
|
||||
@@ -205,17 +250,12 @@
|
||||
}
|
||||
|
||||
const loadDataTable = async (res) => {
|
||||
return await List({ ...params.value, ...res, ...searchFormRef.value.formModel });
|
||||
return await List({ ...params.value, ...res, ...searchFormRef.value?.formModel });
|
||||
};
|
||||
|
||||
function onCheckedRow(rowKeys) {
|
||||
console.log(rowKeys);
|
||||
if (rowKeys.length > 0) {
|
||||
batchDeleteDisabled.value = false;
|
||||
} else {
|
||||
batchDeleteDisabled.value = true;
|
||||
}
|
||||
|
||||
batchDeleteDisabled.value = rowKeys.length <= 0;
|
||||
checkedIds.value = rowKeys;
|
||||
}
|
||||
|
||||
@@ -228,10 +268,8 @@
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('formParams:' + JSON.stringify(formParams.value));
|
||||
Edit(formParams.value)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
@@ -250,31 +288,24 @@
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
showModal.value = true;
|
||||
formParams.value = record;
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
console.log('点击了删除', record);
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
// message.error(e.message ?? '操作失败');
|
||||
});
|
||||
Delete(record).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -284,11 +315,10 @@
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete({ id: checkedIds.value })
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
@@ -297,13 +327,12 @@
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleSubmit(values: Recordable) {
|
||||
console.log(values);
|
||||
params.value = values;
|
||||
reloadTable();
|
||||
}
|
||||
@@ -314,18 +343,26 @@
|
||||
}
|
||||
|
||||
function updateStatus(id, status) {
|
||||
Status({ id: id, status: status })
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
reloadTable({});
|
||||
});
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
Status({ id: id, status: status }).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
reloadTable();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function loadOptions() {
|
||||
options.value.status = await Dict('sys_normal_disable');
|
||||
for (const item of schemas.value) {
|
||||
if (item.field === 'status') {
|
||||
item.componentProps.options = options.value.status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await loadOptions();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
|
||||
@@ -169,10 +169,6 @@
|
||||
});
|
||||
}
|
||||
|
||||
function resetForm() {
|
||||
formRef.value.restoreValidation();
|
||||
}
|
||||
|
||||
function uploadChange(list: string[]) {
|
||||
// 单图模式,只需要第一个索引
|
||||
if (list.length > 0) {
|
||||
|
||||
@@ -10,7 +10,11 @@
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="SMTP端口" path="smtpPort">
|
||||
<n-input v-model:value="formValue.smtpPort" placeholder="" />
|
||||
<n-input-number
|
||||
v-model:value="formValue.smtpPort"
|
||||
placeholder=""
|
||||
:show-button="false"
|
||||
/>
|
||||
<template #feedback> (不加密默认25,SSL默认465,TLS默认587)</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="SMTP用户名" path="smtpUser">
|
||||
@@ -19,7 +23,7 @@
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="SMTP密码" path="smtpPass">
|
||||
<n-input v-model:value="formValue.smtpPass" placeholder="" />
|
||||
<n-input v-model:value="formValue.smtpPass" placeholder="" type="password" />
|
||||
<template #feedback>填写您的密码</template>
|
||||
</n-form-item>
|
||||
|
||||
@@ -117,13 +121,9 @@
|
||||
console.log('formParams:' + JSON.stringify(formParams.value));
|
||||
|
||||
showModal.value = false;
|
||||
sendTestEmail(formParams.value)
|
||||
.then((_res) => {
|
||||
message.success('发送成功');
|
||||
})
|
||||
.catch((error) => {
|
||||
// message.error(error.toString());
|
||||
});
|
||||
sendTestEmail(formParams.value).then((_res) => {
|
||||
message.success('发送成功');
|
||||
});
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
|
||||
87
web/src/views/system/config/GeoSetting.vue
Normal file
87
web/src/views/system/config/GeoSetting.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-spin :show="show" description="正在获取配置...">
|
||||
<n-grid cols="2 s:2 m:2 l:2 xl:2 2xl:2" responsive="screen">
|
||||
<n-grid-item>
|
||||
<n-form :label-width="100" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="高德Web服务key" path="geoAmapWebKey">
|
||||
<n-input v-model:value="formValue.geoAmapWebKey" placeholder="" type="password" />
|
||||
<template #feedback> 申请地址:https://console.amap.com/dev/key/app</template>
|
||||
</n-form-item>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</n-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { getConfig, updateConfig } from '@/api/sys/config';
|
||||
|
||||
const group = ref('geo');
|
||||
const show = ref(false);
|
||||
|
||||
const rules = {
|
||||
geoAmapWebKey: {
|
||||
required: true,
|
||||
message: '请输入高德Web服务key',
|
||||
trigger: 'blur',
|
||||
},
|
||||
};
|
||||
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
|
||||
const formValue = ref({
|
||||
geoAmapWebKey: '',
|
||||
});
|
||||
|
||||
function formSubmit() {
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('formValue.value:' + JSON.stringify(formValue.value));
|
||||
|
||||
updateConfig({ group: group.value, list: formValue.value })
|
||||
.then((res) => {
|
||||
console.log('res:' + JSON.stringify(res));
|
||||
message.success('更新成功');
|
||||
load();
|
||||
})
|
||||
.catch((error) => {
|
||||
message.error(error.toString());
|
||||
});
|
||||
} else {
|
||||
message.error('验证失败,请填写完整信息');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
load();
|
||||
});
|
||||
|
||||
function load() {
|
||||
show.value = true;
|
||||
new Promise((_resolve, _reject) => {
|
||||
getConfig({ group: group.value })
|
||||
.then((res) => {
|
||||
show.value = false;
|
||||
// state.formValue.watermarkClarity = res;
|
||||
formValue.value = res.list;
|
||||
console.log('res:' + JSON.stringify(res));
|
||||
})
|
||||
.catch((error) => {
|
||||
show.value = false;
|
||||
message.error(error.toString());
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@@ -90,7 +90,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, reactive, ref, toRefs } from 'vue';
|
||||
import { useDialog, useMessage } from 'naive-ui';
|
||||
import { useMessage } from 'naive-ui';
|
||||
|
||||
const rules = {
|
||||
name: {
|
||||
@@ -156,8 +156,6 @@
|
||||
setup() {
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
const dialog = useDialog();
|
||||
|
||||
const state = reactive({
|
||||
formValue: {
|
||||
bigWidth: '',
|
||||
@@ -171,23 +169,6 @@
|
||||
},
|
||||
});
|
||||
|
||||
function systemOpenChange(value) {
|
||||
if (!value) {
|
||||
dialog.warning({
|
||||
title: '提示',
|
||||
content: '您确定要关闭系统访问吗?该操作立马生效,请慎重操作!',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
message.success('操作成功');
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
state.formValue.systemOpen = true;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function formSubmit() {
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
@@ -211,7 +192,6 @@
|
||||
rules,
|
||||
formSubmit,
|
||||
resetForm,
|
||||
systemOpenChange,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
167
web/src/views/system/config/SmsSetting.vue
Normal file
167
web/src/views/system/config/SmsSetting.vue
Normal file
@@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-spin :show="show" description="正在获取配置...">
|
||||
<n-grid cols="2 s:2 m:2 l:2 xl:2 2xl:2" responsive="screen">
|
||||
<n-grid-item>
|
||||
<n-divider title-placement="left">通用配置</n-divider>
|
||||
<n-form :label-width="100" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="默认驱动" path="smsDrive">
|
||||
<n-select
|
||||
placeholder="默认发送驱动"
|
||||
:options="driveList"
|
||||
v-model:value="formValue.smsDrive"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="最小发送间隔" path="smsMinInterval">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.smsMinInterval"
|
||||
>
|
||||
<template #suffix> 秒 </template>
|
||||
</n-input-number>
|
||||
<template #feedback> 同号码</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="IP最大发送次数" path="smsMaxIpLimit">
|
||||
<n-input-number v-model:value="formValue.smsMaxIpLimit" placeholder="" />
|
||||
<template #feedback> 同IP每天最大允许发送次数 </template>
|
||||
</n-form-item>
|
||||
<n-form-item label="验证码有效期" path="smsCodeExpire">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.smsCodeExpire"
|
||||
>
|
||||
<template #suffix> 秒 </template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
|
||||
<n-divider title-placement="left">阿里云</n-divider>
|
||||
<n-form-item label="AccessKeyID" path="smsAliyunAccessKeyID">
|
||||
<n-input
|
||||
v-model:value="formValue.smsAliyunAccessKeyID"
|
||||
placeholder=""
|
||||
type="password"
|
||||
/>
|
||||
<template #feedback
|
||||
>应用key和密钥你可以通过 https://ram.console.aliyun.com/manage/ak 获取</template
|
||||
>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="AccessKeySecret" path="smsAliyunAccessKeySecret">
|
||||
<n-input
|
||||
type="password"
|
||||
v-model:value="formValue.smsAliyunAccessKeySecret"
|
||||
placeholder=""
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="签名" path="smsAliyunSign">
|
||||
<n-input v-model:value="formValue.smsAliyunSign" placeholder="" />
|
||||
<template #feedback
|
||||
>申请地址:https://dysms.console.aliyun.com/domestic/text/sign</template
|
||||
>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="短信模板" path="smsAliyunTemplate">
|
||||
<n-dynamic-input
|
||||
v-model:value="formValue.smsAliyunTemplate"
|
||||
preset="pair"
|
||||
key-placeholder="key"
|
||||
value-placeholder="模板CODE"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</n-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { getConfig, updateConfig } from '@/api/sys/config';
|
||||
|
||||
const group = ref('sms');
|
||||
const show = ref(false);
|
||||
|
||||
const rules = {
|
||||
smsDrive: {
|
||||
required: true,
|
||||
message: '请输入默认驱动',
|
||||
trigger: 'blur',
|
||||
},
|
||||
};
|
||||
|
||||
const driveList = [
|
||||
{
|
||||
label: '阿里云',
|
||||
value: 'aliyun',
|
||||
},
|
||||
{
|
||||
label: '腾讯云',
|
||||
value: 'tencent',
|
||||
},
|
||||
];
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
|
||||
const formValue = ref({
|
||||
smsDrive: 'aliyun',
|
||||
smsAliyunAccessKeyID: '',
|
||||
smsAliyunAccessKeySecret: '',
|
||||
smsAliyunSign: '',
|
||||
smsAliyunTemplate: null,
|
||||
smsMinInterval: 60,
|
||||
smsMaxIpLimit: 10,
|
||||
smsCodeExpire: 600,
|
||||
});
|
||||
|
||||
function formSubmit() {
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('formValue.value:' + JSON.stringify(formValue.value));
|
||||
|
||||
updateConfig({ group: group.value, list: formValue.value })
|
||||
.then((res) => {
|
||||
console.log('res:' + JSON.stringify(res));
|
||||
message.success('更新成功');
|
||||
load();
|
||||
})
|
||||
.catch((error) => {
|
||||
message.error(error.toString());
|
||||
});
|
||||
} else {
|
||||
message.error('验证失败,请填写完整信息');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
load();
|
||||
});
|
||||
|
||||
function load() {
|
||||
show.value = true;
|
||||
new Promise((_resolve, _reject) => {
|
||||
getConfig({ group: group.value })
|
||||
.then((res) => {
|
||||
show.value = false;
|
||||
res.list.smsAliyunTemplate = JSON.parse(res.list.smsAliyunTemplate);
|
||||
formValue.value = res.list;
|
||||
})
|
||||
.catch((error) => {
|
||||
show.value = false;
|
||||
message.error(error.toString());
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
177
web/src/views/system/config/UploadSetting.vue
Normal file
177
web/src/views/system/config/UploadSetting.vue
Normal file
@@ -0,0 +1,177 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-spin :show="show" description="正在获取配置...">
|
||||
<n-grid cols="2 s:2 m:2 l:2 xl:2 2xl:2" responsive="screen">
|
||||
<n-grid-item>
|
||||
<n-divider title-placement="left">通用配置</n-divider>
|
||||
<n-form :label-width="100" :model="formValue" :rules="rules" ref="formRef">
|
||||
<n-form-item label="默认驱动" path="uploadDrive">
|
||||
<n-select
|
||||
placeholder="默认驱动"
|
||||
:options="uploadDriveList"
|
||||
v-model:value="formValue.uploadDrive"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="图片大小限制" path="uploadImageSize">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.uploadImageSize"
|
||||
>
|
||||
<template #suffix> MB </template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
<n-form-item label="图片类型限制" path="uploadImageType">
|
||||
<n-input v-model:value="formValue.uploadImageType" placeholder="" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="文件大小限制" path="uploadFileSize">
|
||||
<n-input-number
|
||||
:show-button="false"
|
||||
placeholder="请输入"
|
||||
v-model:value="formValue.uploadFileSize"
|
||||
>
|
||||
<template #suffix> MB </template>
|
||||
</n-input-number>
|
||||
</n-form-item>
|
||||
<n-form-item label="文件类型限制" path="uploadFileType">
|
||||
<n-input v-model:value="formValue.uploadFileType" placeholder="" />
|
||||
</n-form-item>
|
||||
|
||||
<n-divider title-placement="left">本地存储</n-divider>
|
||||
<n-form-item label="本地存储路径" path="uploadLocalPath">
|
||||
<n-input v-model:value="formValue.uploadLocalPath" placeholder="" />
|
||||
<template #feedback>填对外访问的相对路径</template>
|
||||
</n-form-item>
|
||||
|
||||
<n-divider title-placement="left">UCloud存储</n-divider>
|
||||
<n-form-item label="公钥" path="uploadUCloudPublicKey">
|
||||
<n-input
|
||||
v-model:value="formValue.uploadUCloudPublicKey"
|
||||
placeholder=""
|
||||
type="password"
|
||||
/>
|
||||
<template #feedback>获取地址:https://console.ucloud.cn/ufile/token</template>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="私钥" path="uploadUCloudPrivateKey">
|
||||
<n-input
|
||||
v-model:value="formValue.uploadUCloudPrivateKey"
|
||||
placeholder=""
|
||||
type="password"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="存储路径" path="uploadUCloudPath">
|
||||
<n-input v-model:value="formValue.uploadUCloudPath" placeholder="" />
|
||||
<template #feedback>填对对象存储中的相对路径</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="地域API" path="uploadUCloudBucketHost">
|
||||
<n-input v-model:value="formValue.uploadUCloudBucketHost" placeholder="" />
|
||||
</n-form-item>
|
||||
<n-form-item label="存储桶名称" path="uploadUCloudBucketName">
|
||||
<n-input v-model:value="formValue.uploadUCloudBucketName" placeholder="" />
|
||||
<template #feedback>存储空间名称</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="存储桶地域host" path="uploadUCloudFileHost">
|
||||
<n-input v-model:value="formValue.uploadUCloudFileHost" placeholder="" />
|
||||
<template #feedback>不需要包含桶名称</template>
|
||||
</n-form-item>
|
||||
<n-form-item label="访问域名" path="uploadUCloudEndpoint">
|
||||
<n-input v-model:value="formValue.uploadUCloudEndpoint" placeholder="" />
|
||||
<template #feedback>格式,http://abc.com 或 https://abc.com,不可为空</template>
|
||||
</n-form-item>
|
||||
<div>
|
||||
<n-space>
|
||||
<n-button type="primary" @click="formSubmit">保存更新</n-button>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-form>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
</n-spin>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { getConfig, updateConfig } from '@/api/sys/config';
|
||||
|
||||
const group = ref('upload');
|
||||
const show = ref(false);
|
||||
|
||||
const rules = {
|
||||
uploadDrive: {
|
||||
required: true,
|
||||
message: '请输入默认驱动',
|
||||
trigger: 'blur',
|
||||
},
|
||||
};
|
||||
|
||||
const uploadDriveList = [
|
||||
{
|
||||
label: '本地存储',
|
||||
value: 'local',
|
||||
},
|
||||
{
|
||||
label: 'UC云存储',
|
||||
value: 'ucloud',
|
||||
},
|
||||
];
|
||||
|
||||
const formRef: any = ref(null);
|
||||
const message = useMessage();
|
||||
|
||||
const formValue = ref({
|
||||
uploadDrive: 'local',
|
||||
uploadImageSize: 2,
|
||||
uploadImageType: '',
|
||||
uploadFileSize: 10,
|
||||
uploadFileType: '',
|
||||
uploadLocalPath: '',
|
||||
uploadUCloudPath: '',
|
||||
uploadUCloudPublicKey: '',
|
||||
uploadUCloudPrivateKey: '',
|
||||
uploadUCloudBucketHost: 'api.ucloud.cn',
|
||||
uploadUCloudBucketName: '',
|
||||
uploadUCloudFileHost: 'cn-bj.ufileos.com',
|
||||
uploadUCloudEndpoint: '',
|
||||
});
|
||||
|
||||
function formSubmit() {
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('formValue.value:' + JSON.stringify(formValue.value));
|
||||
|
||||
updateConfig({ group: group.value, list: formValue.value }).then((res) => {
|
||||
console.log('res:' + JSON.stringify(res));
|
||||
message.success('更新成功');
|
||||
load();
|
||||
});
|
||||
} else {
|
||||
message.error('验证失败,请填写完整信息');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
load();
|
||||
});
|
||||
|
||||
function load() {
|
||||
show.value = true;
|
||||
new Promise((_resolve, _reject) => {
|
||||
getConfig({ group: group.value })
|
||||
.then((res) => {
|
||||
show.value = false;
|
||||
formValue.value = res.list;
|
||||
console.log('res:' + JSON.stringify(res));
|
||||
})
|
||||
.catch((error) => {
|
||||
show.value = false;
|
||||
message.error(error.toString());
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
@@ -21,6 +21,9 @@
|
||||
<ThemeSetting v-if="type === 2" />
|
||||
<RevealSetting v-if="type === 3" />
|
||||
<EmailSetting v-if="type === 4" />
|
||||
<UploadSetting v-if="type === 8" />
|
||||
<GeoSetting v-if="type === 9" />
|
||||
<SmsSetting v-if="type === 10" />
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
</n-grid>
|
||||
@@ -32,7 +35,9 @@
|
||||
import RevealSetting from './RevealSetting.vue';
|
||||
import EmailSetting from './EmailSetting.vue';
|
||||
import ThemeSetting from './ThemeSetting.vue';
|
||||
|
||||
import UploadSetting from './UploadSetting.vue';
|
||||
import GeoSetting from './GeoSetting.vue';
|
||||
import SmsSetting from './SmsSetting.vue';
|
||||
const typeTabList = [
|
||||
{
|
||||
name: '基本设置',
|
||||
@@ -54,9 +59,47 @@
|
||||
desc: '系统邮件设置',
|
||||
key: 4,
|
||||
},
|
||||
// {
|
||||
// name: '客服设置',
|
||||
// desc: '系统客服设置',
|
||||
// key: 5,
|
||||
// },
|
||||
// {
|
||||
// name: '下游配置',
|
||||
// desc: '默认设置和权限屏蔽',
|
||||
// key: 6,
|
||||
// },
|
||||
// {
|
||||
// name: '提现配置',
|
||||
// desc: '提现规则配置',
|
||||
// key: 7,
|
||||
// },
|
||||
{
|
||||
name: '云存储',
|
||||
desc: '配置上传文件驱动',
|
||||
key: 8,
|
||||
},
|
||||
{
|
||||
name: '地理位置',
|
||||
desc: '配置地理位置工具',
|
||||
key: 9,
|
||||
},
|
||||
{
|
||||
name: '短信配置',
|
||||
desc: '短信验证码平台',
|
||||
key: 10,
|
||||
},
|
||||
];
|
||||
export default defineComponent({
|
||||
components: { BasicSetting, RevealSetting, EmailSetting, ThemeSetting },
|
||||
components: {
|
||||
BasicSetting,
|
||||
RevealSetting,
|
||||
EmailSetting,
|
||||
ThemeSetting,
|
||||
UploadSetting,
|
||||
GeoSetting,
|
||||
SmsSetting,
|
||||
},
|
||||
setup() {
|
||||
const state = reactive({
|
||||
type: 1,
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:openChecked="true"
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
@@ -149,7 +150,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { h, onMounted, reactive, ref, onBeforeMount } from 'vue';
|
||||
import { h, reactive, ref, onBeforeMount } from 'vue';
|
||||
import { TreeSelectOption, useDialog, useMessage } from 'naive-ui';
|
||||
import { BasicTable, TableAction } from '@/components/Table';
|
||||
import { BasicForm, FormSchema, useForm } from '@/components/Form/index';
|
||||
@@ -159,7 +160,7 @@
|
||||
import { statusActions } from '@/enums/optionsiEnum';
|
||||
import GroupModal from './modal/modal.vue';
|
||||
|
||||
const optionTreeData = ref([]);
|
||||
const optionTreeData = ref<any>([]);
|
||||
const defaultValueRef = () => ({
|
||||
id: 0,
|
||||
groupId: 0,
|
||||
@@ -172,7 +173,7 @@
|
||||
remark: '',
|
||||
status: 1,
|
||||
});
|
||||
const params = ref({
|
||||
const params = ref<any>({
|
||||
pageSize: 10,
|
||||
title: '',
|
||||
content: '',
|
||||
@@ -221,7 +222,7 @@
|
||||
return s;
|
||||
});
|
||||
|
||||
const groupOptions = ref([]);
|
||||
const groupOptions = ref<any>([]);
|
||||
|
||||
const schemas: FormSchema[] = [
|
||||
{
|
||||
@@ -282,11 +283,11 @@
|
||||
const dialog = useDialog();
|
||||
const showModal = ref(false);
|
||||
const formBtnLoading = ref(false);
|
||||
const searchFormRef = ref({});
|
||||
const formRef = ref({});
|
||||
const searchFormRef = ref<any>({});
|
||||
const formRef = ref<any>({});
|
||||
const batchDeleteDisabled = ref(true);
|
||||
const checkedIds = ref([]);
|
||||
let formParams = ref(defaultValueRef());
|
||||
let formParams = ref<any>(defaultValueRef());
|
||||
|
||||
const actionColumn = reactive({
|
||||
width: 320,
|
||||
@@ -330,17 +331,11 @@
|
||||
}
|
||||
|
||||
const loadDataTable = async (res) => {
|
||||
return await List({ ...params.value, ...res, ...searchFormRef.value.formModel });
|
||||
return await List({ ...params.value, ...res, ...searchFormRef.value?.formModel });
|
||||
};
|
||||
|
||||
function onCheckedRow(rowKeys) {
|
||||
console.log(rowKeys);
|
||||
if (rowKeys.length > 0) {
|
||||
batchDeleteDisabled.value = false;
|
||||
} else {
|
||||
batchDeleteDisabled.value = true;
|
||||
}
|
||||
|
||||
batchDeleteDisabled.value = rowKeys.length <= 0;
|
||||
checkedIds.value = rowKeys;
|
||||
}
|
||||
|
||||
@@ -353,20 +348,14 @@
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('formParams:' + JSON.stringify(formParams.value));
|
||||
Edit(formParams.value)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
reloadTable();
|
||||
formParams.value = ref(defaultValueRef());
|
||||
});
|
||||
})
|
||||
.catch((_e: Error) => {
|
||||
// message.error(e.message ?? '操作失败');
|
||||
Edit(formParams.value).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
reloadTable();
|
||||
formParams.value = ref(defaultValueRef());
|
||||
});
|
||||
});
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
@@ -375,35 +364,29 @@
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
showModal.value = true;
|
||||
formParams.value = record;
|
||||
}
|
||||
|
||||
function handleExecute(record: Recordable) {
|
||||
console.log('点击了handleExecute', record);
|
||||
message.error('暂未配置');
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
console.log('点击了删除', record);
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
// message.error(e.message ?? '操作失败');
|
||||
});
|
||||
Delete(record).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -413,26 +396,20 @@
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete({ id: checkedIds.value })
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
});
|
||||
Delete({ id: checkedIds.value }).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleSubmit(values: Recordable) {
|
||||
console.log(values);
|
||||
params.value = values;
|
||||
reloadTable();
|
||||
}
|
||||
@@ -448,7 +425,7 @@
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
reloadTable({});
|
||||
reloadTable();
|
||||
});
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
@@ -485,9 +462,8 @@
|
||||
// 处理选项更新
|
||||
function handleUpdateValue(
|
||||
value: string | number | Array<string | number> | null,
|
||||
option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
_option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
) {
|
||||
console.log(value, option);
|
||||
formParams.value.groupId = value;
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -78,12 +78,12 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { h, reactive, ref, onMounted } from 'vue';
|
||||
import { SelectOption, TreeSelectOption, useDialog, useMessage } from 'naive-ui';
|
||||
import { TreeSelectOption, useDialog, useMessage } from 'naive-ui';
|
||||
import { BasicTable, TableAction } from '@/components/Table';
|
||||
import { columns } from './columns';
|
||||
import { PlusOutlined } from '@vicons/antd';
|
||||
import { GroupDelete, GroupEdit, GroupList, GroupStatus, getSelect } from '@/api/sys/cron';
|
||||
import { statusActions, statusOptions } from '@/enums/optionsiEnum';
|
||||
import { GroupDelete, GroupEdit, GroupList, getSelect } from '@/api/sys/cron';
|
||||
import { statusOptions } from '@/enums/optionsiEnum';
|
||||
|
||||
const optionTreeData = ref([]);
|
||||
const message = useMessage();
|
||||
@@ -118,18 +118,12 @@
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('formParams.value:' + JSON.stringify(formParams.value));
|
||||
GroupEdit(formParams.value)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
GroupEdit(formParams.value).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
reloadTable();
|
||||
});
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
reloadTable();
|
||||
});
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
@@ -140,12 +134,9 @@
|
||||
|
||||
const dialog = useDialog();
|
||||
const actionRef = ref();
|
||||
const formParams = ref<any>(defaultValueRef);
|
||||
const formRef = ref<any>({});
|
||||
|
||||
const formParams = ref(defaultValueRef);
|
||||
|
||||
const params = ref(defaultValueRef);
|
||||
|
||||
const formRef = ref({});
|
||||
const actionColumn = reactive({
|
||||
width: 220,
|
||||
title: '操作',
|
||||
@@ -169,7 +160,6 @@
|
||||
});
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('handleEdit', record);
|
||||
showModal.value = true;
|
||||
modalTitle.value = '编辑分组 ID:' + record.id;
|
||||
formParams.value = {
|
||||
@@ -183,25 +173,20 @@
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
console.log('点击了删除', record);
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
GroupDelete(record)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((_e: Error) => {
|
||||
// message.error(e.message ?? '操作失败');
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -232,15 +217,14 @@
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
setDictSelect();
|
||||
await setDictSelect();
|
||||
});
|
||||
|
||||
// 处理选项更新
|
||||
function handleUpdateValue(
|
||||
value: string | number | Array<string | number> | null,
|
||||
option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
_option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
) {
|
||||
console.log(value, option);
|
||||
formParams.value.pid = value;
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -87,8 +87,7 @@
|
||||
default: '添加顶级菜单',
|
||||
},
|
||||
optionTreeData: {
|
||||
type: Object,
|
||||
// eslint-disable-next-line vue/require-valid-default-prop
|
||||
type: Object || Array,
|
||||
default: [],
|
||||
},
|
||||
},
|
||||
@@ -106,7 +105,7 @@
|
||||
sort: 10,
|
||||
});
|
||||
|
||||
const state = reactive({
|
||||
const state = reactive<any>({
|
||||
width: 500,
|
||||
isDrawer: false,
|
||||
subLoading: false,
|
||||
@@ -122,7 +121,6 @@
|
||||
state.width = document.body.clientWidth;
|
||||
}
|
||||
state.isDrawer = true;
|
||||
console.log('form:' + JSON.stringify(form));
|
||||
state.formParams = Object.assign(state.formParams, form);
|
||||
}
|
||||
|
||||
@@ -133,18 +131,12 @@
|
||||
function formSubmit() {
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('state.formParams:' + JSON.stringify(state.formParams));
|
||||
EditDict({ ...state.formParams })
|
||||
.then(async (_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
handleReset();
|
||||
await context.emit('loadData');
|
||||
closeDrawer();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
});
|
||||
EditDict({ ...state.formParams }).then(async (_res) => {
|
||||
message.success('操作成功');
|
||||
handleReset();
|
||||
await context.emit('loadData');
|
||||
closeDrawer();
|
||||
});
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
@@ -159,9 +151,8 @@
|
||||
// 处理选项更新
|
||||
function handleUpdateValue(
|
||||
value: string | number | Array<string | number> | null,
|
||||
option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
_option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
) {
|
||||
console.log(value, option);
|
||||
state.formParams.pid = value;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,17 +12,46 @@ export const columns = [
|
||||
},
|
||||
{
|
||||
title: '字典标签',
|
||||
key: 'label',
|
||||
key: 'type',
|
||||
render(row) {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
type: row.listClass,
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => row.label,
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '字典键值',
|
||||
key: 'value',
|
||||
},
|
||||
|
||||
// {
|
||||
// title: '备注',
|
||||
// key: 'remark',
|
||||
// },
|
||||
{
|
||||
title: '键值类型',
|
||||
key: 'valueType',
|
||||
render(row) {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
type: 'default',
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => row.valueType,
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
@@ -42,9 +71,4 @@ export const columns = [
|
||||
);
|
||||
},
|
||||
},
|
||||
// {
|
||||
// title: '创建时间',
|
||||
// key: 'createdAt',
|
||||
// width: 100,
|
||||
// },
|
||||
];
|
||||
|
||||
@@ -28,7 +28,12 @@
|
||||
</template>
|
||||
</BasicTable>
|
||||
|
||||
<n-modal v-model:show="showModal" :show-icon="false" preset="dialog" title="新建">
|
||||
<n-modal
|
||||
v-model:show="showModal"
|
||||
:show-icon="false"
|
||||
preset="dialog"
|
||||
:title="formParams?.id > 0 ? '编辑' : '新建'"
|
||||
>
|
||||
<n-form
|
||||
:model="formParams"
|
||||
:rules="rules"
|
||||
@@ -51,11 +56,14 @@
|
||||
<n-form-item label="字典键值" path="value">
|
||||
<n-input placeholder="请输入键值" v-model:value="formParams.value" />
|
||||
</n-form-item>
|
||||
<n-form-item label="表格回显" path="listClass">
|
||||
<n-input placeholder="请输入表格回显样式" v-model:value="formParams.listClass" />
|
||||
<n-form-item label="键值类型" path="valueType">
|
||||
<n-select v-model:value="formParams.valueType" :options="options" />
|
||||
</n-form-item>
|
||||
<n-form-item label="标签样式" path="listClass">
|
||||
<n-select v-model:value="formParams.listClass" :options="tagOptions" />
|
||||
</n-form-item>
|
||||
<n-form-item label="排序" path="sort">
|
||||
<n-input placeholder="请输入" v-model:value="formParams.sort" />
|
||||
<n-input-number placeholder="请输入" v-model:value="formParams.sort" />
|
||||
</n-form-item>
|
||||
<n-form-item label="状态" path="status">
|
||||
<n-radio-group v-model:value="formParams.status" name="status">
|
||||
@@ -91,8 +99,10 @@
|
||||
import { getDataList, getDictSelect, EditData, DeleteData } from '@/api/dict/dict';
|
||||
import { columns } from './columns';
|
||||
import { PlusOutlined } from '@vicons/antd';
|
||||
import { statusOptions } from '@/enums/optionsiEnum';
|
||||
|
||||
import { statusOptions, tagOptions } from '@/enums/optionsiEnum';
|
||||
import { TypeSelect } from '@/api/sys/config';
|
||||
import { Option } from '@/utils/hotgo';
|
||||
const options = ref<Option>();
|
||||
interface Props {
|
||||
checkedId?: number;
|
||||
}
|
||||
@@ -115,7 +125,6 @@
|
||||
const schemas: FormSchema[] = [
|
||||
{
|
||||
field: 'label',
|
||||
// labelMessage: '请输入字典标签名称',
|
||||
component: 'NInput',
|
||||
label: '标签',
|
||||
componentProps: {
|
||||
@@ -135,18 +144,7 @@
|
||||
const actionRef = ref();
|
||||
const showModal = ref(false);
|
||||
const formBtnLoading = ref(false);
|
||||
|
||||
const resetFormParams = {
|
||||
typeId: props.checkedId,
|
||||
label: '',
|
||||
value: '',
|
||||
listClass: '',
|
||||
sort: 0,
|
||||
status: 1,
|
||||
remark: '',
|
||||
};
|
||||
const formParams = ref(resetFormParams);
|
||||
|
||||
const formParams = ref<any>({ typeId: 0 });
|
||||
const params = ref({
|
||||
pageSize: 10,
|
||||
typeId: props.checkedId,
|
||||
@@ -162,14 +160,14 @@
|
||||
return h(TableAction as any, {
|
||||
style: 'button',
|
||||
actions: [
|
||||
{
|
||||
label: '删除',
|
||||
onClick: handleDelete.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
onClick: handleDelete.bind(null, record),
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
@@ -183,7 +181,16 @@
|
||||
|
||||
function addTable() {
|
||||
showModal.value = true;
|
||||
formParams.value = resetFormParams;
|
||||
formParams.value = {
|
||||
typeId: props.checkedId,
|
||||
label: '',
|
||||
value: '',
|
||||
listClass: 'default',
|
||||
valueType: 'string',
|
||||
sort: 0,
|
||||
status: 1,
|
||||
remark: '',
|
||||
};
|
||||
}
|
||||
|
||||
const loadDataTable = async (res) => {
|
||||
@@ -203,20 +210,13 @@
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
console.log('formParams:' + JSON.stringify(formParams.value));
|
||||
EditData(formParams.value)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
reloadTable();
|
||||
formParams.value = ref(resetFormParams);
|
||||
});
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
message.error(e.message ?? '操作失败');
|
||||
EditData(formParams.value).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
showModal.value = false;
|
||||
reloadTable();
|
||||
});
|
||||
});
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
@@ -230,47 +230,37 @@
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '不确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
DeleteData(record)
|
||||
.then((_res) => {
|
||||
console.log('_res:' + JSON.stringify(_res));
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
// message.error(e.message ?? '操作失败');
|
||||
});
|
||||
DeleteData(record).then((_res) => {
|
||||
message.success('操作成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('不确定');
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
showModal.value = true;
|
||||
formParams.value = record;
|
||||
}
|
||||
|
||||
function handleSubmit(values: Recordable) {
|
||||
console.log(values);
|
||||
function handleSubmit(_values: Recordable) {
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
function handleReset(values: Recordable) {
|
||||
console.log(values);
|
||||
function handleReset(_values: Recordable) {
|
||||
params.value.label = '';
|
||||
reloadTable();
|
||||
}
|
||||
|
||||
watch(props, (_newVal, _oldVal) => {
|
||||
console.log('_newVal:' + JSON.stringify(_newVal));
|
||||
params.value.typeId = _newVal.checkedId;
|
||||
formParams.value.typeId = _newVal.checkedId;
|
||||
actionRef.value.reload();
|
||||
|
||||
setDictSelect();
|
||||
});
|
||||
|
||||
@@ -283,15 +273,18 @@
|
||||
|
||||
function handleUpdateTypeIdValue(
|
||||
value: string | number | Array<string | number> | null,
|
||||
option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
_option: TreeSelectOption | null | Array<TreeSelectOption | null>
|
||||
) {
|
||||
console.log(value, option);
|
||||
|
||||
formParams.value.typeId = value;
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
setDictSelect();
|
||||
async function loadOptions() {
|
||||
options.value = await TypeSelect();
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
await setDictSelect();
|
||||
await loadOptions();
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
233
web/src/views/test/edit.vue
Normal file
233
web/src/views/test/edit.vue
Normal file
@@ -0,0 +1,233 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-modal
|
||||
v-model:show="isShowModal"
|
||||
:show-icon="false"
|
||||
preset="dialog"
|
||||
:title="params?.id > 0 ? '编辑 #' + params?.id : '新建'"
|
||||
:style="{
|
||||
width: dialogWidth,
|
||||
}"
|
||||
>
|
||||
<n-form
|
||||
:model="params"
|
||||
:rules="rules"
|
||||
ref="formRef"
|
||||
label-placement="left"
|
||||
:label-width="80"
|
||||
class="py-4"
|
||||
>
|
||||
<n-form-item label="标题" path="title">
|
||||
<n-input placeholder="请输入标题" v-model:value="params.title" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="分类ID" path="categoryId">
|
||||
<n-input-number placeholder="请输入分类ID" v-model:value="params.categoryId" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="标签" path="flag">
|
||||
<n-checkbox-group v-model:value="params.flag">
|
||||
<n-space>
|
||||
<n-checkbox
|
||||
v-for="item in options.sys_notice_type"
|
||||
:key="item.value"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
/>
|
||||
</n-space>
|
||||
</n-checkbox-group>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="描述" path="description">
|
||||
<n-input type="textarea" placeholder="描述" v-model:value="params.description" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="内容" path="content">
|
||||
<Editor style="height: 450px" v-model:value="params.content" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="单图" path="image">
|
||||
<UploadImage :maxNumber="1" v-model:value="params.image" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="多图" path="images">
|
||||
<UploadImage :maxNumber="10" v-model:value="params.images" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="单附件" path="attachfile">
|
||||
<UploadFile :maxNumber="1" v-model:value="params.attachfile" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="多附件" path="attachfiles">
|
||||
<UploadFile :maxNumber="10" v-model:value="params.attachfiles" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="键值对" path="map">
|
||||
<n-dynamic-input
|
||||
v-model:value="params.map"
|
||||
preset="pair"
|
||||
key-placeholder="键名"
|
||||
value-placeholder="键值"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="推荐星" path="star">
|
||||
<n-rate allow-half :default-value="params.star" :on-update:value="updateStar" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="价格" path="price">
|
||||
<n-input-number
|
||||
placeholder="请输入价格"
|
||||
clearable
|
||||
v-model:value="params.price"
|
||||
:precision="2"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="活动时间" path="activityAt">
|
||||
<DatePicker v-model:formValue="params.activityAt" type="date" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="开放时间" path="startAt">
|
||||
<DatePicker
|
||||
v-model:startValue="params.startAt"
|
||||
v-model:endValue="params.endAt"
|
||||
type="datetimerange"
|
||||
/>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="用户渠道" path="channel">
|
||||
<n-select v-model:value="params.channel" :options="options.sys_user_channel" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="用户爱好" path="hobby">
|
||||
<n-select multiple v-model:value="params.hobby" :options="options.sys_user_hobby" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="QQ" path="qq">
|
||||
<n-input placeholder="请输入QQ号" v-model:value="params.qq" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="邮箱" path="email">
|
||||
<n-input placeholder="请输入邮箱地址" v-model:value="params.email" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="手机号" path="mobile">
|
||||
<n-input placeholder="请输入手机号" v-model:value="params.mobile" />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="排序" path="sort">
|
||||
<n-input-number v-model:value="params.sort" clearable />
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="状态" path="status">
|
||||
<n-radio-group v-model:value="params.status" name="status">
|
||||
<n-radio-button
|
||||
v-for="status in options.sys_normal_disable"
|
||||
:key="Number(status.value)"
|
||||
:value="Number(status.value)"
|
||||
:label="status.label"
|
||||
/>
|
||||
</n-radio-group>
|
||||
</n-form-item>
|
||||
|
||||
<n-form-item label="备注" path="remark">
|
||||
<n-input type="textarea" placeholder="请输入备注" v-model:value="params.remark" />
|
||||
</n-form-item>
|
||||
</n-form>
|
||||
|
||||
<template #action>
|
||||
<n-space>
|
||||
<n-button @click="closeForm">取消</n-button>
|
||||
<n-button type="info" :loading="formBtnLoading" @click="confirmForm">确定</n-button>
|
||||
</n-space>
|
||||
</template>
|
||||
</n-modal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, ref, computed, watch } from 'vue';
|
||||
import { rules, options, State, newState } from './model';
|
||||
import { Edit, MaxSort } from '@/api/test';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { adaModalWidth } from '@/utils/hotgo';
|
||||
import DatePicker from '@/components/DatePicker/datePicker.vue';
|
||||
import Editor from '@/components/Editor/editor.vue';
|
||||
import UploadImage from '@/components/Upload/uploadImage.vue';
|
||||
import UploadFile from '@/components/Upload/uploadFile.vue';
|
||||
const emit = defineEmits(['reloadTable', 'updateShowModal']);
|
||||
|
||||
interface Props {
|
||||
showModal: boolean;
|
||||
formParams?: State;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
showModal: false,
|
||||
formParams: () => {
|
||||
return newState(null);
|
||||
},
|
||||
});
|
||||
|
||||
const isShowModal = computed({
|
||||
get: () => {
|
||||
return props.showModal;
|
||||
},
|
||||
set: (value) => {
|
||||
emit('updateShowModal', value);
|
||||
},
|
||||
});
|
||||
|
||||
const params = computed(() => {
|
||||
return props.formParams;
|
||||
});
|
||||
|
||||
const message = useMessage();
|
||||
const formRef = ref<any>({});
|
||||
const dialogWidth = ref('75%');
|
||||
const formBtnLoading = ref(false);
|
||||
|
||||
function confirmForm(e) {
|
||||
e.preventDefault();
|
||||
formBtnLoading.value = true;
|
||||
formRef.value.validate((errors) => {
|
||||
if (!errors) {
|
||||
Edit(params.value).then((_res) => {
|
||||
message.success('操作成功');
|
||||
setTimeout(() => {
|
||||
isShowModal.value = false;
|
||||
emit('reloadTable');
|
||||
});
|
||||
});
|
||||
} else {
|
||||
message.error('请填写完整信息');
|
||||
}
|
||||
formBtnLoading.value = false;
|
||||
});
|
||||
}
|
||||
|
||||
function updateStar(num) {
|
||||
params.value.star = num;
|
||||
}
|
||||
|
||||
function closeForm() {
|
||||
isShowModal.value = false;
|
||||
}
|
||||
|
||||
watch(
|
||||
() => params.value,
|
||||
(value) => {
|
||||
if (value.id === 0) {
|
||||
MaxSort().then((res) => {
|
||||
params.value.sort = res.sort;
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
onMounted(async () => {
|
||||
adaModalWidth(dialogWidth);
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less"></style>
|
||||
256
web/src/views/test/index.vue
Normal file
256
web/src/views/test/index.vue
Normal file
@@ -0,0 +1,256 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-card :bordered="false" class="proCard">
|
||||
<div class="n-layout-page-header">
|
||||
<n-card :bordered="false" title="普通表格演示">
|
||||
这里提供了一些常用的普通表格组件的用法和表单组件的例子
|
||||
</n-card>
|
||||
</div>
|
||||
<BasicForm
|
||||
@register="register"
|
||||
@submit="reloadTable"
|
||||
@reset="reloadTable"
|
||||
@keyup.enter="reloadTable"
|
||||
ref="searchFormRef"
|
||||
>
|
||||
<template #statusSlot="{ model, field }">
|
||||
<n-input v-model:value="model[field]" />
|
||||
</template>
|
||||
</BasicForm>
|
||||
|
||||
<BasicTable
|
||||
:openChecked="true"
|
||||
:columns="columns"
|
||||
:request="loadDataTable"
|
||||
:row-key="(row) => row.id"
|
||||
ref="actionRef"
|
||||
:actionColumn="actionColumn"
|
||||
@update:checked-row-keys="onCheckedRow"
|
||||
:scroll-x="1090"
|
||||
:resizeHeightOffset="-10000"
|
||||
size="small"
|
||||
>
|
||||
<template #tableTitle>
|
||||
<n-button
|
||||
type="primary"
|
||||
@click="addTable"
|
||||
class="min-left-space"
|
||||
v-if="hasPermission(['/guide/auth.html'])"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<PlusOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
新建
|
||||
</n-button>
|
||||
<n-button
|
||||
type="error"
|
||||
@click="handleBatchDelete"
|
||||
:disabled="batchDeleteDisabled"
|
||||
class="min-left-space"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<DeleteOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
批量删除
|
||||
</n-button>
|
||||
<n-button type="primary" @click="handleExport" class="min-left-space">
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<ExportOutlined />
|
||||
</n-icon>
|
||||
</template>
|
||||
导出
|
||||
</n-button>
|
||||
</template>
|
||||
</BasicTable>
|
||||
</n-card>
|
||||
<Edit
|
||||
@reloadTable="reloadTable"
|
||||
@updateShowModal="updateShowModal"
|
||||
:showModal="showModal"
|
||||
:formParams="formParams"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { h, reactive, ref } from 'vue';
|
||||
import { useDialog, useMessage } from 'naive-ui';
|
||||
import { BasicTable, TableAction } from '@/components/Table';
|
||||
import { BasicForm, useForm } from '@/components/Form/index';
|
||||
import { usePermission } from '@/hooks/web/usePermission';
|
||||
import { Delete, List, Status, Export } from '@/api/test';
|
||||
import { State, columns, schemas, options, newState } from './model';
|
||||
import { DeleteOutlined, PlusOutlined, ExportOutlined } from '@vicons/antd';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { getOptionLabel } from '@/utils/hotgo';
|
||||
import Edit from './edit.vue';
|
||||
|
||||
const { hasPermission } = usePermission();
|
||||
const router = useRouter();
|
||||
const actionRef = ref();
|
||||
const dialog = useDialog();
|
||||
const message = useMessage();
|
||||
const searchFormRef = ref<any>({});
|
||||
const batchDeleteDisabled = ref(true);
|
||||
const checkedIds = ref([]);
|
||||
const showModal = ref(false);
|
||||
const formParams = ref<State>();
|
||||
|
||||
const actionColumn = reactive({
|
||||
width: 300,
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
// fixed: 'right',
|
||||
render(record) {
|
||||
return h(TableAction as any, {
|
||||
style: 'button',
|
||||
actions: [
|
||||
{
|
||||
label: '编辑',
|
||||
onClick: handleEdit.bind(null, record),
|
||||
// auth: ['basic_list'],
|
||||
},
|
||||
{
|
||||
label: '禁用',
|
||||
onClick: handleStatus.bind(null, record, 2),
|
||||
ifShow: () => {
|
||||
return record.status === 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '启用',
|
||||
onClick: handleStatus.bind(null, record, 1),
|
||||
ifShow: () => {
|
||||
return record.status === 2;
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
onClick: handleDelete.bind(null, record),
|
||||
},
|
||||
],
|
||||
dropDownActions: [
|
||||
{
|
||||
label: '查看详情',
|
||||
key: 'view',
|
||||
},
|
||||
{
|
||||
label: '更多按钮1',
|
||||
key: 'test1',
|
||||
// 根据业务控制是否显示: 非enable状态的不显示启用按钮
|
||||
ifShow: () => {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
{
|
||||
label: '更多按钮2',
|
||||
key: 'test2',
|
||||
ifShow: () => {
|
||||
return true;
|
||||
},
|
||||
},
|
||||
],
|
||||
select: (key) => {
|
||||
if (key === 'view') {
|
||||
return handleView(record);
|
||||
}
|
||||
message.info(`您点击了,${key} 按钮`);
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const [register, {}] = useForm({
|
||||
gridProps: { cols: '1 s:1 m:2 l:3 xl:4 2xl:4' },
|
||||
labelWidth: 80,
|
||||
schemas,
|
||||
});
|
||||
|
||||
const loadDataTable = async (res) => {
|
||||
return await List({ ...searchFormRef.value?.formModel, ...res });
|
||||
};
|
||||
|
||||
function addTable() {
|
||||
showModal.value = true;
|
||||
formParams.value = newState(null);
|
||||
}
|
||||
|
||||
function updateShowModal(value) {
|
||||
showModal.value = value;
|
||||
}
|
||||
|
||||
function onCheckedRow(rowKeys) {
|
||||
batchDeleteDisabled.value = rowKeys.length <= 0;
|
||||
checkedIds.value = rowKeys;
|
||||
}
|
||||
|
||||
function reloadTable() {
|
||||
actionRef.value.reload();
|
||||
}
|
||||
|
||||
function handleView(record: Recordable) {
|
||||
router.push({ name: 'test_view', params: { id: record.id } });
|
||||
}
|
||||
|
||||
function handleEdit(record: Recordable) {
|
||||
showModal.value = true;
|
||||
formParams.value = newState(record as State);
|
||||
}
|
||||
|
||||
function handleDelete(record: Recordable) {
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete(record).then((_res) => {
|
||||
message.success('删除成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleBatchDelete() {
|
||||
dialog.warning({
|
||||
title: '警告',
|
||||
content: '你确定要批量删除?',
|
||||
positiveText: '确定',
|
||||
negativeText: '取消',
|
||||
onPositiveClick: () => {
|
||||
Delete({ id: checkedIds.value }).then((_res) => {
|
||||
message.success('删除成功');
|
||||
reloadTable();
|
||||
});
|
||||
},
|
||||
onNegativeClick: () => {
|
||||
// message.error('取消');
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleExport() {
|
||||
message.loading('正在导出列表...', { duration: 1200 });
|
||||
Export(searchFormRef.value?.formModel);
|
||||
}
|
||||
|
||||
function handleStatus(record: Recordable, status: number) {
|
||||
Status({ id: record.id, status: status }).then((_res) => {
|
||||
message.success('设为' + getOptionLabel(options.value.sys_normal_disable, status) + '成功');
|
||||
setTimeout(() => {
|
||||
reloadTable();
|
||||
});
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
519
web/src/views/test/model.ts
Normal file
519
web/src/views/test/model.ts
Normal file
@@ -0,0 +1,519 @@
|
||||
import { h, ref } from 'vue';
|
||||
import { NAvatar, NImage, NTag, NSwitch, NRate } from 'naive-ui';
|
||||
import { cloneDeep } from 'lodash-es';
|
||||
import { FormSchema } from '@/components/Form';
|
||||
import { Dicts } from '@/api/dict/dict';
|
||||
import { Switch } from '@/api/test';
|
||||
import { isNullObject } from '@/utils/is';
|
||||
import { getFileExt } from '@/utils/urlUtils';
|
||||
import { defRangeShortcuts, defShortcuts, formatToDate } from '@/utils/dateUtil';
|
||||
import { validate } from '@/utils/validateUtil';
|
||||
import { getOptionLabel, getOptionTag, Options } from '@/utils/hotgo';
|
||||
import { usePermission } from '@/hooks/web/usePermission';
|
||||
const { hasPermission } = usePermission();
|
||||
const $message = window['$message'];
|
||||
export interface State {
|
||||
id: number;
|
||||
memberId: number;
|
||||
categoryId: number;
|
||||
flag: number[] | null;
|
||||
title: string;
|
||||
content: string;
|
||||
image: string;
|
||||
images: string[] | null;
|
||||
attachfile: string;
|
||||
attachfiles: string[] | null;
|
||||
map: unknown[] | null;
|
||||
star: number;
|
||||
description: string;
|
||||
price: number;
|
||||
views: number;
|
||||
activityAt: string;
|
||||
startAt: null;
|
||||
endAt: null;
|
||||
switch: number;
|
||||
sort: number;
|
||||
avatar: string;
|
||||
sex: number;
|
||||
qq: string;
|
||||
email: string;
|
||||
mobile: string;
|
||||
channel: number;
|
||||
hobby: string[] | null;
|
||||
pid: number;
|
||||
level: number;
|
||||
tree: string;
|
||||
remark: string;
|
||||
status: number;
|
||||
createdBy: number;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export const defaultState = {
|
||||
id: 0,
|
||||
memberId: 0,
|
||||
categoryId: 0,
|
||||
flag: [1],
|
||||
title: '',
|
||||
content: '',
|
||||
image: '',
|
||||
images: null,
|
||||
attachfile: '',
|
||||
attachfiles: null,
|
||||
map: null,
|
||||
star: 0,
|
||||
description: '',
|
||||
price: 0,
|
||||
views: 0,
|
||||
activityAt: '',
|
||||
startAt: null,
|
||||
endAt: null,
|
||||
switch: 0,
|
||||
sort: 0,
|
||||
avatar: '',
|
||||
sex: 0,
|
||||
qq: '',
|
||||
email: '',
|
||||
mobile: '',
|
||||
channel: 0,
|
||||
hobby: null,
|
||||
pid: 0,
|
||||
level: 1,
|
||||
tree: '',
|
||||
remark: '',
|
||||
status: 1,
|
||||
createdBy: 0,
|
||||
createdAt: '',
|
||||
updatedAt: '',
|
||||
};
|
||||
|
||||
export function newState(state: State | null): State {
|
||||
if (state !== null) {
|
||||
return cloneDeep(state);
|
||||
}
|
||||
return cloneDeep(defaultState);
|
||||
}
|
||||
|
||||
export const options = ref<Options>({
|
||||
sys_normal_disable: [],
|
||||
sys_user_sex: [],
|
||||
sys_notice_type: [],
|
||||
sys_user_channel: [],
|
||||
sys_user_hobby: [],
|
||||
sys_switch: [],
|
||||
});
|
||||
|
||||
export const rules = {
|
||||
title: {
|
||||
required: true,
|
||||
trigger: ['blur', 'input'],
|
||||
message: '请输入标题',
|
||||
},
|
||||
price: {
|
||||
required: true,
|
||||
trigger: ['blur', 'input'],
|
||||
validator: validate.amount,
|
||||
},
|
||||
qq: {
|
||||
required: false,
|
||||
trigger: ['blur', 'input'],
|
||||
validator: validate.qq,
|
||||
},
|
||||
email: {
|
||||
required: true,
|
||||
trigger: ['blur', 'input'],
|
||||
validator: validate.email,
|
||||
},
|
||||
mobile: {
|
||||
required: true,
|
||||
trigger: ['blur', 'input'],
|
||||
validator: validate.phone,
|
||||
},
|
||||
};
|
||||
|
||||
export const schemas = ref<FormSchema[]>([
|
||||
{
|
||||
field: 'title',
|
||||
component: 'NInput',
|
||||
label: '标题',
|
||||
componentProps: {
|
||||
placeholder: '请输入标题',
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
rules: [{ message: '请输入标题', trigger: ['blur'] }],
|
||||
},
|
||||
{
|
||||
field: 'content',
|
||||
component: 'NInput',
|
||||
label: '内容',
|
||||
componentProps: {
|
||||
placeholder: '请输入内容关键词',
|
||||
showButton: false,
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'price',
|
||||
labelMessage: '我是自定义提示',
|
||||
component: 'NInput',
|
||||
label: '价格',
|
||||
componentProps: {
|
||||
pair: true,
|
||||
separator: '-',
|
||||
clearable: true,
|
||||
placeholder: ['从', '到'],
|
||||
onInput: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'activityAt',
|
||||
component: 'NDatePicker',
|
||||
label: '活动时间',
|
||||
componentProps: {
|
||||
type: 'date',
|
||||
clearable: true,
|
||||
shortcuts: defShortcuts(),
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'createdAt',
|
||||
component: 'NDatePicker',
|
||||
label: '创建时间',
|
||||
componentProps: {
|
||||
type: 'datetimerange',
|
||||
clearable: true,
|
||||
shortcuts: defRangeShortcuts(),
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'flag',
|
||||
component: 'NCheckbox',
|
||||
label: '标签',
|
||||
giProps: {
|
||||
span: 1,
|
||||
},
|
||||
componentProps: {
|
||||
placeholder: '请选择标签',
|
||||
options: [],
|
||||
onUpdateChecked: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'switch',
|
||||
component: 'NRadioGroup',
|
||||
label: '开关',
|
||||
giProps: {
|
||||
//span: 24,
|
||||
},
|
||||
componentProps: {
|
||||
options: [],
|
||||
onUpdateChecked: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'hobby',
|
||||
component: 'NSelect',
|
||||
label: '爱好',
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
multiple: true,
|
||||
placeholder: '请选择爱好',
|
||||
options: [],
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
component: 'NSelect',
|
||||
label: '状态',
|
||||
defaultValue: null,
|
||||
componentProps: {
|
||||
placeholder: '请选择类型',
|
||||
options: [],
|
||||
onUpdateValue: (e: any) => {
|
||||
console.log(e);
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
export const columns = [
|
||||
{
|
||||
title: 'ID',
|
||||
key: 'id',
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
key: 'title',
|
||||
render(row) {
|
||||
return row.title;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '标签',
|
||||
key: 'flag',
|
||||
render(row) {
|
||||
if (isNullObject(row.flag)) {
|
||||
return ``;
|
||||
}
|
||||
return row.flag.map((tagKey) => {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
type: getOptionTag(options.value.sys_notice_type, tagKey),
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => getOptionLabel(options.value.sys_notice_type, tagKey),
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '单图',
|
||||
key: 'image',
|
||||
render(row) {
|
||||
return h(NImage, {
|
||||
width: 32,
|
||||
height: 32,
|
||||
src: row.image,
|
||||
style: {
|
||||
width: '32px',
|
||||
height: '32px',
|
||||
'max-width': '100%',
|
||||
'max-height': '100%',
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '多图',
|
||||
key: 'images',
|
||||
render(row) {
|
||||
if (isNullObject(row.images)) {
|
||||
return ``;
|
||||
}
|
||||
return row.images.map((image) => {
|
||||
return h(NImage, {
|
||||
width: 32,
|
||||
height: 32,
|
||||
src: image,
|
||||
style: {
|
||||
width: '32px',
|
||||
height: '32px',
|
||||
'max-width': '100%',
|
||||
'max-height': '100%',
|
||||
'margin-left': '2px',
|
||||
},
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '附件',
|
||||
key: 'attachfile',
|
||||
render(row) {
|
||||
if (row.attachfile === '') {
|
||||
return ``;
|
||||
}
|
||||
return h(
|
||||
NAvatar,
|
||||
{
|
||||
size: 'small',
|
||||
},
|
||||
{
|
||||
default: () => getFileExt(row.attachfile),
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '多附件',
|
||||
key: 'attachfiles',
|
||||
render(row) {
|
||||
if (isNullObject(row.attachfiles)) {
|
||||
return ``;
|
||||
}
|
||||
return row.attachfiles.map((attachfile) => {
|
||||
return h(
|
||||
NAvatar,
|
||||
{
|
||||
size: 'small',
|
||||
style: {
|
||||
'margin-left': '2px',
|
||||
},
|
||||
},
|
||||
{
|
||||
default: () => getFileExt(attachfile),
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '推荐星',
|
||||
key: 'star',
|
||||
// width: 180,
|
||||
render(row) {
|
||||
return h(NRate, {
|
||||
allowHalf: true,
|
||||
readonly: true,
|
||||
defaultValue: row.star,
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
key: 'description',
|
||||
},
|
||||
{
|
||||
title: '价格',
|
||||
key: 'price',
|
||||
render(row) {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
type: 'success',
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => row.price.toFixed(2),
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '开关',
|
||||
key: 'switch',
|
||||
width: 100,
|
||||
render(row) {
|
||||
return h(NSwitch, {
|
||||
value: row.switch === 1,
|
||||
checked: '开启',
|
||||
unchecked: '关闭',
|
||||
disabled: hasPermission(['asd']),
|
||||
onUpdateValue: function (e) {
|
||||
console.log('onUpdateValue e:' + JSON.stringify(e));
|
||||
row.switch = e ? 1 : 2;
|
||||
Switch({ id: row.id, key: 'switch', value: row.switch }).then((_res) => {
|
||||
$message.success('操作成功');
|
||||
});
|
||||
},
|
||||
});
|
||||
},
|
||||
},
|
||||
// {
|
||||
// title: '排序',
|
||||
// key: 'sort',
|
||||
// },
|
||||
{
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
render(row) {
|
||||
if (isNullObject(row.status)) {
|
||||
return ``;
|
||||
}
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
type: getOptionTag(options.value.sys_normal_disable, row.status),
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => getOptionLabel(options.value.sys_normal_disable, row.status),
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '爱好',
|
||||
key: 'hobby',
|
||||
render(row) {
|
||||
if (isNullObject(row.hobby)) {
|
||||
return ``;
|
||||
}
|
||||
return row.hobby.map((tagKey) => {
|
||||
return h(
|
||||
NTag,
|
||||
{
|
||||
style: {
|
||||
marginRight: '6px',
|
||||
},
|
||||
type: getOptionTag(options.value.sys_user_hobby, tagKey),
|
||||
bordered: false,
|
||||
},
|
||||
{
|
||||
default: () => getOptionLabel(options.value.sys_user_hobby, tagKey),
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '活动时间',
|
||||
key: 'activityAt',
|
||||
render(row) {
|
||||
return formatToDate(row.activityAt);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
async function loadOptions() {
|
||||
options.value = await Dicts({
|
||||
types: [
|
||||
'sys_normal_disable',
|
||||
'sys_user_sex',
|
||||
'sys_notice_type',
|
||||
'sys_switch',
|
||||
'sys_user_hobby',
|
||||
'sys_user_channel',
|
||||
],
|
||||
});
|
||||
for (const item of schemas.value) {
|
||||
switch (item.field) {
|
||||
case 'status':
|
||||
item.componentProps.options = options.value.sys_normal_disable;
|
||||
break;
|
||||
case 'flag':
|
||||
item.componentProps.options = options.value.sys_notice_type;
|
||||
break;
|
||||
case 'switch':
|
||||
item.componentProps.options = options.value.sys_switch;
|
||||
break;
|
||||
case 'hobby':
|
||||
item.componentProps.options = options.value.sys_user_hobby;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await loadOptions();
|
||||
142
web/src/views/test/view.vue
Normal file
142
web/src/views/test/view.vue
Normal file
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="n-layout-page-header">
|
||||
<n-card :bordered="false" title="基础详情"> 基础详情,有时也用于显示只读信息。 </n-card>
|
||||
</div>
|
||||
<n-card :bordered="false" class="proCard mt-4" size="small" :segmented="{ content: true }">
|
||||
<n-descriptions label-placement="left" class="py-2" column="4">
|
||||
<n-descriptions-item>
|
||||
<template #label>分类ID</template>
|
||||
{{ formValue.categoryId }}
|
||||
</n-descriptions-item>
|
||||
|
||||
<n-descriptions-item label="标签">
|
||||
<template v-for="(item, key) in formValue?.flag" :key="key">
|
||||
<n-tag
|
||||
:type="getOptionTag(options.sys_notice_type, item)"
|
||||
size="small"
|
||||
class="min-left-space"
|
||||
>{{ getOptionLabel(options.sys_notice_type, item) }}</n-tag
|
||||
>
|
||||
</template>
|
||||
</n-descriptions-item>
|
||||
<n-descriptions-item label="标题">{{ formValue.title }}</n-descriptions-item>
|
||||
<n-descriptions-item label="描述">{{ formValue.description }}</n-descriptions-item>
|
||||
<n-descriptions-item label="推荐星"
|
||||
><n-rate readonly :default-value="formValue.star"
|
||||
/></n-descriptions-item>
|
||||
<n-descriptions-item label="价格">{{ formValue.price }}</n-descriptions-item>
|
||||
<n-descriptions-item label="浏览次数">{{ formValue.views }}</n-descriptions-item>
|
||||
<n-descriptions-item label="活动时间">{{ formValue.activityAt }}</n-descriptions-item>
|
||||
<n-descriptions-item label="开关">
|
||||
<n-switch v-model:value="formValue.switch" :unchecked-value="2" :checked-value="1"
|
||||
/></n-descriptions-item>
|
||||
<n-descriptions-item label="创建人ID">{{ formValue.createdBy }} </n-descriptions-item>
|
||||
<n-descriptions-item label="创建时间">{{ formValue.createdAt }} </n-descriptions-item>
|
||||
</n-descriptions>
|
||||
</n-card>
|
||||
|
||||
<n-card :bordered="false" class="proCard mt-4" size="small" :segmented="{ content: true }">
|
||||
<n-descriptions label-placement="top" title="内容" class="py-2" column="1">
|
||||
<n-descriptions-item><span v-html="formValue.content"></span></n-descriptions-item>
|
||||
</n-descriptions>
|
||||
</n-card>
|
||||
|
||||
<n-card :bordered="false" class="proCard mt-4" size="small" :segmented="{ content: true }">
|
||||
<n-descriptions label-placement="top" title="单图" class="py-2" column="1">
|
||||
<n-descriptions-item>
|
||||
<n-image style="margin-left: 10px; height: 100px; width: 100px" :src="formValue.image"
|
||||
/></n-descriptions-item>
|
||||
</n-descriptions>
|
||||
|
||||
<n-descriptions label-placement="top" title="多图" class="py-2" column="1">
|
||||
<n-descriptions-item>
|
||||
<n-image-group>
|
||||
<n-space>
|
||||
<span v-for="(item, key) in formValue?.images" :key="key">
|
||||
<n-image style="margin-left: 10px; height: 100px; width: 100px" :src="item" />
|
||||
</span>
|
||||
</n-space>
|
||||
</n-image-group>
|
||||
</n-descriptions-item>
|
||||
</n-descriptions>
|
||||
|
||||
<n-descriptions label-placement="top" title="附件" class="py-2" column="1">
|
||||
<n-descriptions-item>
|
||||
<div
|
||||
class="upload-card"
|
||||
v-show="formValue.attachfile !== ''"
|
||||
@click="download(formValue.attachfile)"
|
||||
>
|
||||
<div class="upload-card-item" style="height: 100px; width: 100px">
|
||||
<div class="upload-card-item-info">
|
||||
<div class="img-box">
|
||||
<n-avatar :style="fileAvatarCSS">{{ getFileExt(formValue.attachfile) }}</n-avatar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</n-descriptions-item>
|
||||
</n-descriptions>
|
||||
|
||||
<n-descriptions label-placement="top" title="多附件" class="py-2" column="1">
|
||||
<n-descriptions-item>
|
||||
<div class="upload-card">
|
||||
<n-space style="gap: 0px 0px">
|
||||
<div
|
||||
class="upload-card-item"
|
||||
style="height: 100px; width: 100px"
|
||||
v-for="(item, key) in formValue.attachfiles"
|
||||
:key="key"
|
||||
>
|
||||
<div class="upload-card-item-info">
|
||||
<div class="img-box">
|
||||
<n-avatar :style="fileAvatarCSS" @click="download(item)">{{
|
||||
getFileExt(item)
|
||||
}}</n-avatar>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</n-space>
|
||||
</div>
|
||||
</n-descriptions-item>
|
||||
</n-descriptions>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useMessage } from 'naive-ui';
|
||||
import { View } from '@/api/test';
|
||||
import { newState, options } from './model';
|
||||
import { getOptionLabel, getOptionTag } from '@/utils/hotgo';
|
||||
import { getFileExt } from '@/utils/urlUtils';
|
||||
|
||||
const message = useMessage();
|
||||
const router = useRouter();
|
||||
const id = Number(router.currentRoute.value.params.id);
|
||||
const formValue = ref(newState(null));
|
||||
const fileAvatarCSS = computed(() => {
|
||||
return {
|
||||
'--n-merged-size': `var(--n-avatar-size-override, 80px)`,
|
||||
'--n-font-size': `18px`,
|
||||
};
|
||||
});
|
||||
|
||||
//下载
|
||||
function download(url: string) {
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (id < 1) {
|
||||
message.error('ID不正确,请检查!');
|
||||
return;
|
||||
}
|
||||
formValue.value = await View({ id: id });
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
Reference in New Issue
Block a user