From ff3144e7082bb277242ed1cb9ca7bca6f25cc730 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=98=89=E6=B3=BD?= <136064@qq.com> Date: Wed, 22 Nov 2023 20:10:35 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E6=8C=89=E9=92=AE=E9=89=B4=E6=9D=83=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/resource/generate/default/curd/web.index.vue.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/resource/generate/default/curd/web.index.vue.template b/server/resource/generate/default/curd/web.index.vue.template index 4eba78f..e90d872 100644 --- a/server/resource/generate/default/curd/web.index.vue.template +++ b/server/resource/generate/default/curd/web.index.vue.template @@ -63,7 +63,7 @@ type="primary" @click="handleExport" class="min-left-space" - v-if="hasPermission(['/@{.apiPrefix}/delete'])" + v-if="hasPermission(['/@{.apiPrefix}/export'])" > + ) { return new VAxios( deepMerge( { - timeout: 10 * 1000, + timeout: 30 * 1000, authenticationScheme: '', // 接口前缀 prefixUrl: urlPrefix, diff --git a/web/src/utils/index.ts b/web/src/utils/index.ts index 7b183fc..f64d223 100644 --- a/web/src/utils/index.ts +++ b/web/src/utils/index.ts @@ -192,16 +192,12 @@ export function getTreeItem(data: any[], key?: string | number): any { return result; } -/** - * 找到所有节点 - * */ -const treeAll: any[] = []; - export function getTreeAll(data: any[]): any[] { + const treeAll: any[] = []; data.map((item) => { treeAll.push(item.key); if (item.children && item.children.length) { - getTreeAll(item.children); + treeAll.push(...getTreeAll(item.children)); } }); return treeAll; diff --git a/web/src/views/addons/hgexample/table/index.vue b/web/src/views/addons/hgexample/table/index.vue index a073fb7..492b4ef 100644 --- a/web/src/views/addons/hgexample/table/index.vue +++ b/web/src/views/addons/hgexample/table/index.vue @@ -25,6 +25,7 @@ :row-key="(row) => row.id" ref="actionRef" :actionColumn="actionColumn" + :checked-row-keys="checkedIds" @update:checked-row-keys="onCheckedRow" :scroll-x="1090" :resizeHeightOffset="-10000" @@ -227,6 +228,8 @@ negativeText: '取消', onPositiveClick: () => { Delete({ id: checkedIds.value }).then((_res) => { + batchDeleteDisabled.value = true; + checkedIds.value = []; message.success('删除成功'); reloadTable(); }); diff --git a/web/src/views/addons/hgexample/treeTable/edit.vue b/web/src/views/addons/hgexample/treeTable/edit.vue new file mode 100644 index 0000000..793d11e --- /dev/null +++ b/web/src/views/addons/hgexample/treeTable/edit.vue @@ -0,0 +1,249 @@ + + + + + diff --git a/web/src/views/addons/hgexample/treeTable/index.vue b/web/src/views/addons/hgexample/treeTable/index.vue new file mode 100644 index 0000000..5852c42 --- /dev/null +++ b/web/src/views/addons/hgexample/treeTable/index.vue @@ -0,0 +1,232 @@ + + diff --git a/web/src/views/addons/hgexample/treeTable/list.vue b/web/src/views/addons/hgexample/treeTable/list.vue new file mode 100644 index 0000000..fba5127 --- /dev/null +++ b/web/src/views/addons/hgexample/treeTable/list.vue @@ -0,0 +1,250 @@ + + + + + diff --git a/web/src/views/addons/hgexample/treeTable/model.ts b/web/src/views/addons/hgexample/treeTable/model.ts new file mode 100644 index 0000000..6a76282 --- /dev/null +++ b/web/src/views/addons/hgexample/treeTable/model.ts @@ -0,0 +1,529 @@ +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/addons/hgexample/table'; +import { isNullObject } from '@/utils/is'; +import { getFileExt } from '@/utils/urlUtils'; +import { defRangeShortcuts, defShortcuts, formatToDate } from '@/utils/dateUtil'; +import { validate } from '@/utils/validateUtil'; +import { errorImg, getOptionLabel, getOptionTag, Options } from '@/utils/hotgo'; +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; + cityId: 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, + cityId: 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({ + 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([ + { + 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', + sorter: true, // 单列排序 + }, + { + title: '标题', + key: 'title', + render(row) { + return row.title; + }, + sorter: { + multiple: 1, // 为多列排序的优先级,越高优先级越高 + }, + }, + { + 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, + fallbackSrc: errorImg, + 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, + fallbackSrc: errorImg, + 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', + sorter: { + multiple: 2, // 为多列排序的优先级,越高优先级越高 + }, + 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: '关闭', + onUpdateValue: function (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); + }, + sorter: { + multiple: 3, // 为多列排序的优先级,越高优先级越高 + }, + }, +]; + +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(); diff --git a/web/src/views/curdDemo/index.vue b/web/src/views/curdDemo/index.vue index 59d8355..3c6b606 100644 --- a/web/src/views/curdDemo/index.vue +++ b/web/src/views/curdDemo/index.vue @@ -26,6 +26,7 @@ :row-key="(row) => row.id" ref="actionRef" :actionColumn="actionColumn" + :checked-row-keys="checkedIds" @update:checked-row-keys="onCheckedRow" :scroll-x="1090" :resizeHeightOffset="-10000" @@ -63,7 +64,7 @@ type="primary" @click="handleExport" class="min-left-space" - v-if="hasPermission(['/curdDemo/delete'])" + v-if="hasPermission(['/curdDemo/export'])" > - + diff --git a/web/src/views/system/cron/modal/columns.ts b/web/src/views/system/cron/modal/columns.ts index ff31257..7774dcf 100644 --- a/web/src/views/system/cron/modal/columns.ts +++ b/web/src/views/system/cron/modal/columns.ts @@ -8,34 +8,33 @@ export const columns = [ key: 'id', width: 100, }, - { - title: '上级ID', - dataIndex: 'pid', - key: 'pid', - width: 100, - }, { title: '分组名称', dataIndex: 'name', key: 'name', - width: 200, + width: 150, }, { - title: '是否默认', + title: '上级分组', + dataIndex: 'supName', + key: 'supName', + width: 150, + render(row) { + if (row.supName == ''){ + return '顶级分组'; + } + return row.supName; + }, + }, + { + title: '默认', dataIndex: 'isDefault', key: 'isDefault', render(row) { - return row.is_default === 1 ? '是' : '否'; + return row.isDefault === 1 ? '是' : '否'; }, - width: 100, + width: 80, }, - { - title: '排序', - dataIndex: 'sort', - key: 'sort', - width: 100, - }, - { title: '状态', dataIndex: 'status', @@ -57,6 +56,12 @@ export const columns = [ }, width: 150, }, + // { + // title: '排序', + // dataIndex: 'sort', + // key: 'sort', + // width: 100, + // }, { title: '备注', dataIndex: 'remark', diff --git a/web/src/views/system/cron/modal/index.vue b/web/src/views/system/cron/modal/index.vue index 4d4af93..8e6a1df 100644 --- a/web/src/views/system/cron/modal/index.vue +++ b/web/src/views/system/cron/modal/index.vue @@ -40,16 +40,11 @@ :default-value="formParams.pid" @update:value="handleUpdateValue" /> - - - - - + + + + @@ -87,7 +86,7 @@ import { statusOptions } from '@/enums/optionsiEnum'; const emit = defineEmits(['reloadGroupOption']); - const optionTreeData = ref([]); + const optionTreeData = ref([]); const message = useMessage(); const statusValue = ref(1); const defaultValueRef = () => ({ @@ -140,7 +139,7 @@ const formRef = ref({}); const actionColumn = reactive({ - width: 220, + width: 150, title: '操作', key: 'action', // fixed: 'right', @@ -213,10 +212,16 @@ async function setDictSelect() { const tmp = await getSelect({}); - optionTreeData.value = tmp.list; - if (optionTreeData.value === undefined || optionTreeData.value === null) { - optionTreeData.value = []; - } + optionTreeData.value = [ + { + id: 0, + key: 0, + label: '顶级分组', + pid: 0, + name: '顶级分组', + }, + ]; + optionTreeData.value = optionTreeData.value.concat(tmp.list); } onMounted(async () => { diff --git a/web/src/views/system/cron/modal/modal.vue b/web/src/views/system/cron/modal/modal.vue index 1e457b0..d851f78 100644 --- a/web/src/views/system/cron/modal/modal.vue +++ b/web/src/views/system/cron/modal/modal.vue @@ -18,7 +18,7 @@ const emit = defineEmits(['reloadGroupOption']); const showModal = ref(false); - const title = ref('管理分组'); + const title = ref('任务分组'); function openDrawer() { showModal.value = true;