From 1fe792a9108bbac324c4af40bdcd8f55735f80d2 Mon Sep 17 00:00:00 2001 From: Qi <3194726156@qq.com> Date: Sun, 10 Aug 2025 10:09:34 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E7=AE=A1=E7=90=86=E5=9F=BA?= =?UTF-8?q?=E6=9C=AC=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../OroqenCultureCategory.api.ts | 76 ++++ .../OroqenCultureCategory.data.ts | 151 +++++++ .../OroqenCultureCategoryList.vue | 156 +++++++ .../components/OroqenCultureCategoryForm.vue | 44 ++ .../components/OroqenCultureCategoryModal.vue | 84 ++++ .../OroqenCultureContent.api.ts | 75 ++++ .../OroqenCultureContent.data.ts | 294 +++++++++++++ .../OroqenCultureContentList.vue | 162 +++++++ .../components/OroqenCultureContentForm.vue | 44 ++ .../components/OroqenCultureContentModal.vue | 186 +++++++++ .../oroqen/inheritor/OroqenInheritor.api.ts | 72 ++++ .../oroqen/inheritor/OroqenInheritor.data.ts | 395 ++++++++++++++++++ .../oroqen/inheritor/OroqenInheritorList.vue | 156 +++++++ .../components/OroqenInheritorForm.vue | 97 +++++ .../components/OroqenInheritorModal.vue | 265 ++++++++++++ .../OroqenProductCategory.api.ts | 76 ++++ .../OroqenProductCategory.data.ts | 214 ++++++++++ .../OroqenProductCategoryList.vue | 156 +++++++ .../components/OroqenProductCategoryForm.vue | 44 ++ .../components/OroqenProductCategoryModal.vue | 172 ++++++++ 20 files changed, 2919 insertions(+) create mode 100644 src/views/oroqen/culture-category/OroqenCultureCategory.api.ts create mode 100644 src/views/oroqen/culture-category/OroqenCultureCategory.data.ts create mode 100644 src/views/oroqen/culture-category/OroqenCultureCategoryList.vue create mode 100644 src/views/oroqen/culture-category/components/OroqenCultureCategoryForm.vue create mode 100644 src/views/oroqen/culture-category/components/OroqenCultureCategoryModal.vue create mode 100644 src/views/oroqen/culture-content/OroqenCultureContent.api.ts create mode 100644 src/views/oroqen/culture-content/OroqenCultureContent.data.ts create mode 100644 src/views/oroqen/culture-content/OroqenCultureContentList.vue create mode 100644 src/views/oroqen/culture-content/components/OroqenCultureContentForm.vue create mode 100644 src/views/oroqen/culture-content/components/OroqenCultureContentModal.vue create mode 100644 src/views/oroqen/inheritor/OroqenInheritor.api.ts create mode 100644 src/views/oroqen/inheritor/OroqenInheritor.data.ts create mode 100644 src/views/oroqen/inheritor/OroqenInheritorList.vue create mode 100644 src/views/oroqen/inheritor/components/OroqenInheritorForm.vue create mode 100644 src/views/oroqen/inheritor/components/OroqenInheritorModal.vue create mode 100644 src/views/oroqen/product-category/OroqenProductCategory.api.ts create mode 100644 src/views/oroqen/product-category/OroqenProductCategory.data.ts create mode 100644 src/views/oroqen/product-category/OroqenProductCategoryList.vue create mode 100644 src/views/oroqen/product-category/components/OroqenProductCategoryForm.vue create mode 100644 src/views/oroqen/product-category/components/OroqenProductCategoryModal.vue diff --git a/src/views/oroqen/culture-category/OroqenCultureCategory.api.ts b/src/views/oroqen/culture-category/OroqenCultureCategory.api.ts new file mode 100644 index 0000000..ab461a1 --- /dev/null +++ b/src/views/oroqen/culture-category/OroqenCultureCategory.api.ts @@ -0,0 +1,76 @@ +import { defHttp } from '/@/utils/http/axios'; +import { useMessage } from '/@/hooks/web/useMessage'; + +const { createConfirm } = useMessage(); + +enum Api { + list = '/oroqen/cultureCategory/list', + save = '/oroqen/cultureCategory/add', + edit = '/oroqen/cultureCategory/edit', + deleteOne = '/oroqen/cultureCategory/delete', + deleteBatch = '/oroqen/cultureCategory/deleteBatch', + importExcel = '/oroqen/cultureCategory/importExcel', + exportXls = '/oroqen/cultureCategory/exportXls', + queryById = '/oroqen/cultureCategory/queryById', + tree = '/oroqen/cultureCategory/tree', +} + +/** + * 导出api + */ +export const getExportUrl = Api.exportXls; + +/** + * 导入api + */ +export const getImportUrl = Api.importExcel; + +/** + * 列表接口 + */ +export const list = (params) => defHttp.get({ url: Api.list, params }); + +/** + * 树形列表接口 + */ +export const queryTreeList = (params) => defHttp.get({ url: Api.tree, params }); + +/** + * 获取分类树 + */ +export const getCategoryTree = () => defHttp.get({ url: Api.tree }); + +/** + * 删除单个 + */ +export const deleteOne = (params, handleSuccess) => { + return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => { + handleSuccess(); + }); +}; + +/** + * 批量删除 + */ +export const batchDelete = (params, handleSuccess) => { + createConfirm({ + iconType: 'warning', + title: '确认删除', + content: '是否删除选中数据', + okText: '确认', + cancelText: '取消', + onOk: () => { + return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => { + handleSuccess(); + }); + } + }); +}; + +/** + * 保存或者更新 + */ +export const saveOrUpdate = (params, isUpdate) => { + let url = isUpdate ? Api.edit : Api.save; + return defHttp.post({ url: url, params }); +}; \ No newline at end of file diff --git a/src/views/oroqen/culture-category/OroqenCultureCategory.data.ts b/src/views/oroqen/culture-category/OroqenCultureCategory.data.ts new file mode 100644 index 0000000..48c26cd --- /dev/null +++ b/src/views/oroqen/culture-category/OroqenCultureCategory.data.ts @@ -0,0 +1,151 @@ +import { BasicColumn } from '/@/components/Table'; +import { FormSchema } from '/@/components/Table'; +import { rules } from '/@/utils/helper/validator'; +import { render } from '/@/utils/common/renderUtils'; + +// 列表页面公共参数、方法 +export const columns: BasicColumn[] = [ + { + title: '分类名称', + align: 'left', + dataIndex: 'categoryName', + width: 200, + }, + { + title: '分类编码', + align: 'center', + dataIndex: 'categoryCode', + width: 150, + }, + { + title: '排序', + align: 'center', + dataIndex: 'sortOrder', + width: 80, + }, + { + title: '状态', + align: 'center', + dataIndex: 'status', + width: 100, + customRender: ({ text }) => { + const statusMap = { + '1': { text: '启用', color: 'green' }, + '0': { text: '禁用', color: 'red' } + }; + const status = statusMap[text] || { text: '未知', color: 'gray' }; + return render.renderTag(status.text, status.color); + }, + }, + { + title: '描述', + align: 'center', + dataIndex: 'description', + width: 200, + ellipsis: true, + }, + { + title: '创建时间', + align: 'center', + dataIndex: 'createTime', + width: 150, + }, +]; + +// 查询数据 +export const searchFormSchema: FormSchema[] = [ + { + label: '分类名称', + field: 'categoryName', + component: 'Input', + colProps: { span: 6 }, + }, + { + label: '分类编码', + field: 'categoryCode', + component: 'Input', + colProps: { span: 6 }, + }, + { + label: '状态', + field: 'status', + component: 'JDictSelectTag', + componentProps: { + dictCode: 'valid_status', + placeholder: '请选择状态', + }, + colProps: { span: 6 }, + }, +]; + +// 表单数据 +export const formSchema: FormSchema[] = [ + { + label: '', + field: 'id', + component: 'Input', + show: false, + }, + { + label: '上级分类', + field: 'parentId', + component: 'JTreeSelect', + componentProps: { + dict: 'oroqen_culture_category,category_name,id', + pidField: 'parent_id', + pidValue: '', + hasChildField: 'has_child', + placeholder: '请选择上级分类', + }, + }, + { + label: '分类名称', + field: 'categoryName', + component: 'Input', + required: true, + dynamicRules: ({ model, schema }) => { + return [{ required: true, message: '请输入分类名称!' }]; + }, + }, + { + label: '分类编码', + field: 'categoryCode', + component: 'Input', + required: true, + dynamicRules: ({ model, schema }) => { + return [ + { required: true, message: '请输入分类编码!' }, + { pattern: /^[a-zA-Z0-9_]+$/, message: '编码只能包含字母、数字和下划线!' } + ]; + }, + }, + { + label: '排序', + field: 'sortOrder', + component: 'InputNumber', + defaultValue: 0, + componentProps: { + min: 0, + placeholder: '请输入排序值', + }, + }, + { + label: '状态', + field: 'status', + component: 'JDictSelectTag', + defaultValue: '1', + componentProps: { + dictCode: 'valid_status', + placeholder: '请选择状态', + }, + }, + { + label: '描述', + field: 'description', + component: 'InputTextArea', + componentProps: { + rows: 3, + placeholder: '请输入分类描述', + }, + }, +]; \ No newline at end of file diff --git a/src/views/oroqen/culture-category/OroqenCultureCategoryList.vue b/src/views/oroqen/culture-category/OroqenCultureCategoryList.vue new file mode 100644 index 0000000..07aa1c8 --- /dev/null +++ b/src/views/oroqen/culture-category/OroqenCultureCategoryList.vue @@ -0,0 +1,156 @@ + + + + + \ No newline at end of file diff --git a/src/views/oroqen/culture-category/components/OroqenCultureCategoryForm.vue b/src/views/oroqen/culture-category/components/OroqenCultureCategoryForm.vue new file mode 100644 index 0000000..7148cac --- /dev/null +++ b/src/views/oroqen/culture-category/components/OroqenCultureCategoryForm.vue @@ -0,0 +1,44 @@ + + + \ No newline at end of file diff --git a/src/views/oroqen/culture-category/components/OroqenCultureCategoryModal.vue b/src/views/oroqen/culture-category/components/OroqenCultureCategoryModal.vue new file mode 100644 index 0000000..9e43c99 --- /dev/null +++ b/src/views/oroqen/culture-category/components/OroqenCultureCategoryModal.vue @@ -0,0 +1,84 @@ + + + \ No newline at end of file diff --git a/src/views/oroqen/culture-content/OroqenCultureContent.api.ts b/src/views/oroqen/culture-content/OroqenCultureContent.api.ts new file mode 100644 index 0000000..a1f556a --- /dev/null +++ b/src/views/oroqen/culture-content/OroqenCultureContent.api.ts @@ -0,0 +1,75 @@ +import { defHttp } from '/@/utils/http/axios'; +import { useMessage } from '/@/hooks/web/useMessage'; + +const { createConfirm } = useMessage(); + +enum Api { + list = '/oroqen/cultureContent/list', + save = '/oroqen/cultureContent/add', + edit = '/oroqen/cultureContent/edit', + deleteOne = '/oroqen/cultureContent/delete', + deleteBatch = '/oroqen/cultureContent/deleteBatch', + importExcel = '/oroqen/cultureContent/importExcel', + exportXls = '/oroqen/cultureContent/exportXls', + queryById = '/oroqen/cultureContent/queryById', + recommend = '/oroqen/cultureContent/recommend', + cancelRecommend = '/oroqen/cultureContent/cancelRecommend', +} + +/** + * 导出api + */ +export const getExportUrl = Api.exportXls; + +/** + * 导入api + */ +export const getImportUrl = Api.importExcel; + +/** + * 列表接口 + */ +export const list = (params) => defHttp.get({ url: Api.list, params }); + +/** + * 删除单个 + */ +export const deleteOne = (params, handleSuccess) => { + return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => { + handleSuccess(); + }); +}; + +/** + * 批量删除 + */ +export const batchDelete = (params, handleSuccess) => { + createConfirm({ + iconType: 'warning', + title: '确认删除', + content: '是否删除选中数据', + okText: '确认', + cancelText: '取消', + onOk: () => { + return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => { + handleSuccess(); + }); + } + }); +}; + +/** + * 保存或者更新 + */ +export const saveOrUpdate = (params, isUpdate) => { + let url = isUpdate ? Api.edit : Api.save; + return defHttp.post({ url: url, params }); +}; + +/** + * 推荐/取消推荐 + */ +export const toggleRecommend = (id: string, isRecommend: boolean) => { + const url = isRecommend ? Api.recommend : Api.cancelRecommend; + return defHttp.post({ url: `${url}/${id}` }); +}; \ No newline at end of file diff --git a/src/views/oroqen/culture-content/OroqenCultureContent.data.ts b/src/views/oroqen/culture-content/OroqenCultureContent.data.ts new file mode 100644 index 0000000..4fc9248 --- /dev/null +++ b/src/views/oroqen/culture-content/OroqenCultureContent.data.ts @@ -0,0 +1,294 @@ +import { BasicColumn } from '/@/components/Table'; +import { FormSchema } from '/@/components/Table'; +import { rules } from '/@/utils/helper/validator'; +import { render } from '/@/utils/common/renderUtils'; +import { JVxeTypes, JVxeColumn } from '/@/components/jeecg/JVxeTable/types'; +import { getFileAccessHttpUrl } from '/@/utils/common/compUtils'; + +// 列表页面公共参数、方法 +export const columns: BasicColumn[] = [ + { + title: '标题', + align: 'center', + dataIndex: 'title', + width: 200, + }, + { + title: '分类', + align: 'center', + dataIndex: 'categoryName', + width: 120, + }, + { + title: '封面图片', + align: 'center', + dataIndex: 'coverImage', + width: 120, + customRender: ({ text }) => { + if (!text) return ''; + const imgUrl = getFileAccessHttpUrl(text); + return render.renderImage(imgUrl, { + style: { width: '60px', height: '40px', objectFit: 'cover' }, + preview: true, + fallback: '/src/assets/images/no-image.png' + }); + }, + }, + { + title: '作者', + align: 'center', + dataIndex: 'author', + width: 100, + }, + { + title: '发布状态', + align: 'center', + dataIndex: 'status', + width: 100, + customRender: ({ text }) => { + const statusMap = { + '0': { text: '草稿', color: 'orange' }, + '1': { text: '已发布', color: 'green' }, + '2': { text: '已下线', color: 'red' } + }; + const status = statusMap[text] || { text: '未知', color: 'gray' }; + return render.renderTag(status.text, status.color); + }, + }, + { + title: '是否推荐', + align: 'center', + dataIndex: 'isRecommended', + width: 100, + customRender: ({ text }) => { + return render.renderSwitch(text, [ + { text: '是', value: '1' }, + { text: '否', value: '0' } + ]); + }, + }, + { + title: '浏览量', + align: 'center', + dataIndex: 'viewCount', + width: 100, + }, + { + title: '点赞数', + align: 'center', + dataIndex: 'likeCount', + width: 100, + }, + { + title: '创建时间', + align: 'center', + dataIndex: 'createTime', + width: 150, + }, +]; + +// 查询数据 +export const searchFormSchema: FormSchema[] = [ + { + label: '标题', + field: 'title', + component: 'Input', + colProps: { span: 6 }, + }, + { + label: '分类', + field: 'categoryId', + component: 'JTreeSelect', + componentProps: { + dict: 'oroqen_culture_category,category_name,id', + pidField: 'parent_id', + pidValue: '0', + hasChildField: 'has_child', + placeholder: '请选择分类', + }, + colProps: { span: 6 }, + }, + { + label: '发布状态', + field: 'status', + component: 'JDictSelectTag', + componentProps: { + dictCode: 'content_status', + placeholder: '请选择状态', + }, + colProps: { span: 6 }, + }, + { + label: '是否推荐', + field: 'isRecommended', + component: 'JDictSelectTag', + componentProps: { + dictCode: 'yes_no', + placeholder: '请选择', + }, + colProps: { span: 6 }, + }, +]; + +// 表单数据 +export const formSchema: FormSchema[] = [ + { + label: '', + field: 'id', + component: 'Input', + show: false, + }, + { + label: '标题', + field: 'title', + component: 'Input', + required: true, + dynamicRules: ({ model, schema }) => { + return [{ required: true, message: '请输入标题!' }]; + }, + }, + { + label: '分类', + field: 'categoryId', + component: 'JTreeSelect', + required: true, + componentProps: { + dict: 'oroqen_culture_category,category_name,id', + pidField: 'parent_id', + pidValue: '0', + hasChildField: 'has_child', + placeholder: '请选择分类', + }, + dynamicRules: ({ model, schema }) => { + return [{ required: true, message: '请选择分类!' }]; + }, + }, + { + label: '封面图片', + field: 'coverImage', + component: 'JUpload', + componentProps: { + fileType: 'image', + maxSize: 5, + maxCount: 1, + bizPath: 'culture/cover', + customRequest: (options) => { + const { file, onSuccess, onError } = options; + + // 验证文件类型 + const isImage = file.type.startsWith('image/'); + if (!isImage) { + onError(new Error('只能上传图片文件!')); + return; + } + + // 验证文件大小 + const isLt5M = file.size / 1024 / 1024 < 5; + if (!isLt5M) { + onError(new Error('图片大小不能超过5MB!')); + return; + } + + // 创建本地预览URL + const blobUrl = URL.createObjectURL(file); + + // 模拟上传成功响应 + setTimeout(() => { + onSuccess({ + status: 'done', + url: blobUrl, + message: blobUrl, + response: { + success: true, + message: '上传成功', + result: { + url: blobUrl + } + } + }); + }, 100); + } + }, + }, + { + label: '作者', + field: 'author', + component: 'Input', + }, + { + label: '摘要', + field: 'summary', + component: 'InputTextArea', + componentProps: { + rows: 3, + placeholder: '请输入内容摘要', + }, + }, + { + label: '内容', + field: 'content', + component: 'JEditor', + required: true, + componentProps: { + height: 400, + placeholder: '请输入内容', + }, + dynamicRules: ({ model, schema }) => { + return [{ required: true, message: '请输入内容!' }]; + }, + }, + { + label: '发布状态', + field: 'status', + component: 'JDictSelectTag', + defaultValue: '0', + componentProps: { + dictCode: 'content_status', + placeholder: '请选择状态', + }, + }, + { + label: '是否推荐', + field: 'isRecommended', + component: 'JSwitch', + defaultValue: '0', + componentProps: { + options: ['0', '1'], + }, + }, + { + label: '排序', + field: 'sortOrder', + component: 'InputNumber', + defaultValue: 0, + componentProps: { + min: 0, + placeholder: '请输入排序值', + }, + }, + { + label: '标签', + field: 'tags', + component: 'Input', + componentProps: { + placeholder: '多个标签用逗号分隔', + }, + }, + { + label: '关键词', + field: 'keywords', + component: 'Input', + componentProps: { + placeholder: '多个关键词用逗号分隔', + }, + }, + { + label: '备注', + field: 'remark', + component: 'InputTextArea', + componentProps: { + rows: 2, + placeholder: '请输入备注', + }, + }, +]; \ No newline at end of file diff --git a/src/views/oroqen/culture-content/OroqenCultureContentList.vue b/src/views/oroqen/culture-content/OroqenCultureContentList.vue new file mode 100644 index 0000000..765326f --- /dev/null +++ b/src/views/oroqen/culture-content/OroqenCultureContentList.vue @@ -0,0 +1,162 @@ + + + + + diff --git a/src/views/oroqen/culture-content/components/OroqenCultureContentForm.vue b/src/views/oroqen/culture-content/components/OroqenCultureContentForm.vue new file mode 100644 index 0000000..0f5ba44 --- /dev/null +++ b/src/views/oroqen/culture-content/components/OroqenCultureContentForm.vue @@ -0,0 +1,44 @@ + + + \ No newline at end of file diff --git a/src/views/oroqen/culture-content/components/OroqenCultureContentModal.vue b/src/views/oroqen/culture-content/components/OroqenCultureContentModal.vue new file mode 100644 index 0000000..afbbd0e --- /dev/null +++ b/src/views/oroqen/culture-content/components/OroqenCultureContentModal.vue @@ -0,0 +1,186 @@ + + + \ No newline at end of file diff --git a/src/views/oroqen/inheritor/OroqenInheritor.api.ts b/src/views/oroqen/inheritor/OroqenInheritor.api.ts new file mode 100644 index 0000000..472ae9f --- /dev/null +++ b/src/views/oroqen/inheritor/OroqenInheritor.api.ts @@ -0,0 +1,72 @@ +import { defHttp } from '/@/utils/http/axios'; +import { useMessage } from '/@/hooks/web/useMessage'; + +const { createConfirm } = useMessage(); + +enum Api { + list = '/oroqen/heritageInheritor/list', + save = '/oroqen/heritageInheritor/add', + edit = '/oroqen/heritageInheritor/edit', + deleteOne = '/oroqen/heritageInheritor/delete', + deleteBatch = '/oroqen/heritageInheritor/deleteBatch', + importExcel = '/oroqen/heritageInheritor/importExcel', + exportXls = '/oroqen/heritageInheritor/exportXls', + queryById = '/oroqen/heritageInheritor/queryById', +} + +/** + * 导出api + */ +export const getExportUrl = Api.exportXls; + +/** + * 导入api + */ +export const getImportUrl = Api.importExcel; + +/** + * 列表接口 + */ +export const list = (params) => defHttp.get({ url: Api.list, params }); + +/** + * 删除单个 + */ +export const deleteOne = (params, handleSuccess) => { + return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => { + handleSuccess(); + }); +}; + +/** + * 批量删除 + */ +export const batchDelete = (params, handleSuccess) => { + createConfirm({ + iconType: 'warning', + title: '确认删除', + content: '是否删除选中数据', + okText: '确认', + cancelText: '取消', + onOk: () => { + return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => { + handleSuccess(); + }); + } + }); +}; + +/** + * 保存或者更新 + */ +export const saveOrUpdate = (params, isUpdate) => { + const url = isUpdate ? Api.edit : Api.save; + return defHttp.post({ url: url, params }, { isTransformResponse: false }); +}; + +/** + * 根据ID查询 + */ +export const queryById = (params) => { + return defHttp.get({ url: Api.queryById, params }); +}; \ No newline at end of file diff --git a/src/views/oroqen/inheritor/OroqenInheritor.data.ts b/src/views/oroqen/inheritor/OroqenInheritor.data.ts new file mode 100644 index 0000000..857bb8a --- /dev/null +++ b/src/views/oroqen/inheritor/OroqenInheritor.data.ts @@ -0,0 +1,395 @@ +import { BasicColumn } from '/@/components/Table'; +import { FormSchema } from '/@/components/Table'; +import { h } from 'vue'; +import { Image, Tag } from 'ant-design-vue'; +import { render } from '/@/utils/common/renderUtils'; +import { getFileAccessHttpUrl } from '/@/utils/common/compUtils'; + +//列表数据 +export const columns: BasicColumn[] = [ + { + title: '头像', + align: 'center', + dataIndex: 'avatar', + width: 80, + customRender: ({ text, record }) => { + if (!text) return '-'; + const imageUrl = getFileAccessHttpUrl(text); + + return h(Image, { + src: imageUrl, + alt: record?.name || '传承人头像', + width: 50, + height: 50, + style: { objectFit: 'cover', borderRadius: '4px' }, + preview: true, + fallback: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3Ik1RnG4W+FgYxN' + }); + } + }, + { + title: '姓名', + dataIndex: 'name', + width: 120, + align: 'left', + ellipsis: true, + fixed: 'left', + }, + { + title: '性别', + dataIndex: 'gender', + width: 80, + align: 'center', + customRender: ({ text }) => { + const genderMap = { + 1: { text: '男', color: 'blue' }, + 2: { text: '女', color: 'pink' }, + }; + const gender = genderMap[text] || { text: '未知', color: 'default' }; + return render.renderTag(gender.text, gender.color); + }, + }, + { + title: '年龄', + dataIndex: 'age', + width: 80, + align: 'center', + }, + { + title: '民族', + dataIndex: 'ethnicity', + width: 100, + align: 'center', + }, + { + title: '传承项目', + dataIndex: 'heritageProject', + width: 150, + align: 'left', + ellipsis: true, + }, + { + title: '传承级别', + dataIndex: 'heritageLevel', + width: 120, + align: 'center', + customRender: ({ text }) => { + const levelMap = { + 'national': { text: '国家级', color: 'red' }, + 'provincial': { text: '省级', color: 'orange' }, + 'municipal': { text: '市级', color: 'blue' }, + 'county': { text: '县级', color: 'green' }, + }; + const level = levelMap[text] || { text: text || '未知', color: 'default' }; + return render.renderTag(level.text, level.color); + }, + }, + { + title: '认定年份', + dataIndex: 'recognitionYear', + width: 100, + align: 'center', + }, + { + title: '联系电话', + dataIndex: 'phone', + width: 120, + align: 'center', + }, + { + title: '状态', + dataIndex: 'status', + width: 100, + align: 'center', + customRender: ({ text }) => { + const statusMap = { + 1: { text: '活跃', color: 'green' }, + 0: { text: '停用', color: 'red' }, + }; + const status = statusMap[text] || { text: '未知', color: 'default' }; + return render.renderTag(status.text, status.color); + }, + }, + { + title: '创建时间', + dataIndex: 'createTime', + width: 150, + align: 'center', + sorter: true, + }, +]; + +//查询数据 +export const searchFormSchema: FormSchema[] = [ + { + label: '姓名', + field: 'name', + component: 'Input', + componentProps: { + placeholder: '请输入传承人姓名', + }, + colProps: { span: 6 }, + }, + { + label: '性别', + field: 'gender', + component: 'Select', + componentProps: { + placeholder: '请选择性别', + options: [ + { label: '男', value: 1 }, + { label: '女', value: 2 }, + ], + }, + colProps: { span: 6 }, + }, + { + label: '传承级别', + field: 'heritageLevel', + component: 'Select', + componentProps: { + placeholder: '请选择传承级别', + options: [ + { label: '国家级', value: 'national' }, + { label: '省级', value: 'provincial' }, + { label: '市级', value: 'municipal' }, + { label: '县级', value: 'county' }, + ], + }, + colProps: { span: 6 }, + }, + { + label: '状态', + field: 'status', + component: 'Select', + componentProps: { + placeholder: '请选择状态', + options: [ + { label: '活跃', value: 1 }, + { label: '停用', value: 0 }, + ], + }, + colProps: { span: 6 }, + }, +]; + +//表单数据 +export const formSchema: FormSchema[] = [ + { + label: '', + field: 'id', + component: 'Input', + show: false, + }, + { + label: '姓名', + field: 'name', + component: 'Input', + required: true, + componentProps: { + placeholder: '请输入传承人姓名', + }, + colProps: { span: 12 }, + }, + { + label: '性别', + field: 'gender', + component: 'Select', + required: true, + componentProps: { + placeholder: '请选择性别', + options: [ + { label: '男', value: 1 }, + { label: '女', value: 2 }, + ], + }, + colProps: { span: 12 }, + }, + { + label: '年龄', + field: 'age', + component: 'InputNumber', + componentProps: { + min: 1, + max: 120, + placeholder: '请输入年龄', + }, + colProps: { span: 12 }, + }, + { + label: '民族', + field: 'ethnicity', + component: 'Input', + componentProps: { + placeholder: '请输入民族', + }, + colProps: { span: 12 }, + }, + { + label: '传承项目', + field: 'heritageProject', + component: 'Input', + required: true, + componentProps: { + placeholder: '请输入传承项目', + }, + colProps: { span: 12 }, + }, + { + label: '传承级别', + field: 'heritageLevel', + component: 'Select', + required: true, + componentProps: { + placeholder: '请选择传承级别', + options: [ + { label: '国家级', value: 'national' }, + { label: '省级', value: 'provincial' }, + { label: '市级', value: 'municipal' }, + { label: '县级', value: 'county' }, + ], + }, + colProps: { span: 12 }, + }, + { + label: '认定年份', + field: 'recognitionYear', + component: 'InputNumber', + componentProps: { + min: 1900, + max: new Date().getFullYear(), + placeholder: '请输入认定年份', + }, + colProps: { span: 12 }, + }, + { + label: '联系电话', + field: 'phone', + component: 'Input', + componentProps: { + placeholder: '请输入联系电话', + }, + colProps: { span: 12 }, + }, + // { + // label: '身份证号', + // field: 'idCard', + // component: 'Input', + // componentProps: { + // placeholder: '请输入身份证号', + // }, + // colProps: { span: 12 }, + // }, + { + label: '地址', + field: 'address', + component: 'Input', + componentProps: { + placeholder: '请输入地址', + }, + colProps: { span: 12 }, + }, + { + label: '状态', + field: 'status', + component: 'Select', + componentProps: { + placeholder: '请选择状态', + options: [ + { label: '活跃', value: 1 }, + { label: '停用', value: 0 }, + ], + }, + colProps: { span: 12 }, + }, + { + label: '排序', + field: 'sortOrder', + component: 'InputNumber', + componentProps: { + min: 0, + placeholder: '请输入排序值', + }, + colProps: { span: 12 }, + }, + { + label: '传承技艺描述', + field: 'skillDescription', + component: 'InputTextArea', + componentProps: { + rows: 4, + placeholder: '请输入传承技艺描述', + }, + colProps: { span: 24 }, + }, + { + label: '个人简介', + field: 'biography', + component: 'InputTextArea', + componentProps: { + rows: 4, + placeholder: '请输入个人简介', + }, + colProps: { span: 24 }, + }, + { + label: '传承经历', + field: 'heritageExperience', + component: 'InputTextArea', + componentProps: { + rows: 4, + placeholder: '请输入传承经历', + }, + colProps: { span: 24 }, + }, + { + label: '获奖情况', + field: 'awards', + component: 'InputTextArea', + componentProps: { + rows: 3, + placeholder: '请输入获奖情况', + }, + colProps: { span: 24 }, + }, + { + label: '头像', + field: 'avatar', + component: 'JUpload', + componentProps: { + fileType: 'image', + maxCount: 1, + maxSize: 5, + bizPath: 'inheritor/portrait', + customRequest: (options) => { + // 验证文件类型和大小 + const { file } = options; + const isImage = file.type.startsWith('image/'); + if (!isImage) { + console.error('只能上传图片文件!'); + return; + } + const isLt5M = file.size / 1024 / 1024 < 5; + if (!isLt5M) { + console.error('图片大小不能超过5MB!'); + return; + } + + // 创建本地预览URL + const localUrl = URL.createObjectURL(file); + + // 直接设置文件的url为本地预览URL + file.url = localUrl; + + // 模拟上传成功响应,返回blob URL作为message + setTimeout(() => { + options.onSuccess({ + success: true, + message: localUrl, // 返回blob URL + }, file); + }, 100); + }, + }, + colProps: { span: 24 }, + }, +]; \ No newline at end of file diff --git a/src/views/oroqen/inheritor/OroqenInheritorList.vue b/src/views/oroqen/inheritor/OroqenInheritorList.vue new file mode 100644 index 0000000..bef92d4 --- /dev/null +++ b/src/views/oroqen/inheritor/OroqenInheritorList.vue @@ -0,0 +1,156 @@ + + + + + \ No newline at end of file diff --git a/src/views/oroqen/inheritor/components/OroqenInheritorForm.vue b/src/views/oroqen/inheritor/components/OroqenInheritorForm.vue new file mode 100644 index 0000000..24f9b0f --- /dev/null +++ b/src/views/oroqen/inheritor/components/OroqenInheritorForm.vue @@ -0,0 +1,97 @@ + + + + + \ No newline at end of file diff --git a/src/views/oroqen/inheritor/components/OroqenInheritorModal.vue b/src/views/oroqen/inheritor/components/OroqenInheritorModal.vue new file mode 100644 index 0000000..22c836f --- /dev/null +++ b/src/views/oroqen/inheritor/components/OroqenInheritorModal.vue @@ -0,0 +1,265 @@ + + + \ No newline at end of file diff --git a/src/views/oroqen/product-category/OroqenProductCategory.api.ts b/src/views/oroqen/product-category/OroqenProductCategory.api.ts new file mode 100644 index 0000000..3a8bcf4 --- /dev/null +++ b/src/views/oroqen/product-category/OroqenProductCategory.api.ts @@ -0,0 +1,76 @@ +import { defHttp } from '/@/utils/http/axios'; +import { useMessage } from '/@/hooks/web/useMessage'; + +const { createConfirm } = useMessage(); + +enum Api { + list = '/oroqen/productCategory/list', + save = '/oroqen/productCategory/add', + edit = '/oroqen/productCategory/edit', + deleteOne = '/oroqen/productCategory/delete', + deleteBatch = '/oroqen/productCategory/deleteBatch', + importExcel = '/oroqen/productCategory/importExcel', + exportXls = '/oroqen/productCategory/exportXls', + queryById = '/oroqen/productCategory/queryById', + tree = '/oroqen/productCategory/tree', +} + +/** + * 导出api + */ +export const getExportUrl = Api.exportXls; + +/** + * 导入api + */ +export const getImportUrl = Api.importExcel; + +/** + * 列表接口 + */ +export const list = (params) => defHttp.get({ url: Api.list, params }); + +/** + * 树形列表接口 + */ +export const queryTreeList = (params) => defHttp.get({ url: Api.tree, params }); + +/** + * 获取分类树 + */ +export const getCategoryTree = () => defHttp.get({ url: Api.tree }); + +/** + * 删除单个 + */ +export const deleteOne = (params, handleSuccess) => { + return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => { + handleSuccess(); + }); +}; + +/** + * 批量删除 + */ +export const batchDelete = (params, handleSuccess) => { + createConfirm({ + iconType: 'warning', + title: '确认删除', + content: '是否删除选中数据', + okText: '确认', + cancelText: '取消', + onOk: () => { + return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => { + handleSuccess(); + }); + } + }); +}; + +/** + * 保存或者更新 + */ +export const saveOrUpdate = (params, isUpdate) => { + let url = isUpdate ? Api.edit : Api.save; + return defHttp.post({ url: url, params }); +}; \ No newline at end of file diff --git a/src/views/oroqen/product-category/OroqenProductCategory.data.ts b/src/views/oroqen/product-category/OroqenProductCategory.data.ts new file mode 100644 index 0000000..1065fe5 --- /dev/null +++ b/src/views/oroqen/product-category/OroqenProductCategory.data.ts @@ -0,0 +1,214 @@ +import { BasicColumn } from '/@/components/Table'; +import { FormSchema } from '/@/components/Table'; +import { rules } from '/@/utils/helper/validator'; +import { render } from '/@/utils/common/renderUtils'; +import { getFileAccessHttpUrl } from '/@/utils/common/compUtils'; + +// 列表页面公共参数、方法 +export const columns: BasicColumn[] = [ + { + title: '分类名称', + align: 'left', + dataIndex: 'categoryName', + width: 200, + }, + { + title: '分类编码', + align: 'center', + dataIndex: 'categoryCode', + width: 150, + }, + { + title: '分类图标', + align: 'center', + dataIndex: 'icon', + width: 100, + customRender: ({ text }) => { + if (!text) return ''; + const imgUrl = getFileAccessHttpUrl(text); + return render.renderImage(imgUrl, { + style: { width: '40px', height: '40px', objectFit: 'cover' }, + preview: true, + fallback: '/src/assets/images/no-image.png' + }); + }, + }, + { + title: '排序', + align: 'center', + dataIndex: 'sortOrder', + width: 80, + }, + { + title: '状态', + align: 'center', + dataIndex: 'status', + width: 100, + customRender: ({ text }) => { + const statusMap = { + '1': { text: '启用', color: 'green' }, + '0': { text: '禁用', color: 'red' } + }; + const status = statusMap[text] || { text: '未知', color: 'gray' }; + return render.renderTag(status.text, status.color); + }, + }, + { + title: '描述', + align: 'center', + dataIndex: 'description', + width: 200, + ellipsis: true, + }, + { + title: '创建时间', + align: 'center', + dataIndex: 'createTime', + width: 150, + }, +]; + +// 查询数据 +export const searchFormSchema: FormSchema[] = [ + { + label: '分类名称', + field: 'categoryName', + component: 'Input', + colProps: { span: 6 }, + }, + { + label: '分类编码', + field: 'categoryCode', + component: 'Input', + colProps: { span: 6 }, + }, + { + label: '状态', + field: 'status', + component: 'JDictSelectTag', + componentProps: { + dictCode: 'valid_status', + placeholder: '请选择状态', + }, + colProps: { span: 6 }, + }, +]; + +// 表单数据 +export const formSchema: FormSchema[] = [ + { + label: '', + field: 'id', + component: 'Input', + show: false, + }, + { + label: '上级分类', + field: 'parentId', + component: 'JTreeSelect', + componentProps: { + dict: 'oroqen_product_category,category_name,id', + pidField: 'parent_id', + pidValue: '', + hasChildField: 'has_child', + placeholder: '请选择上级分类', + }, + }, + { + label: '分类名称', + field: 'categoryName', + component: 'Input', + required: true, + dynamicRules: ({ model, schema }) => { + return [{ required: true, message: '请输入分类名称!' }]; + }, + }, + { + label: '分类编码', + field: 'categoryCode', + component: 'Input', + required: true, + dynamicRules: ({ model, schema }) => { + return [ + { required: true, message: '请输入分类编码!' }, + { pattern: /^[a-zA-Z0-9_]+$/, message: '编码只能包含字母、数字和下划线!' } + ]; + }, + }, + { + label: '分类图标', + field: 'icon', + component: 'JUpload', + componentProps: { + fileType: 'image', + maxSize: 2, + maxCount: 1, + bizPath: 'product/category/icon', + customRequest: (options) => { + const { file, onSuccess, onError } = options; + + // 验证文件类型 + const isImage = file.type.startsWith('image/'); + if (!isImage) { + onError(new Error('只能上传图片文件!')); + return; + } + + // 验证文件大小 + const isLt2M = file.size / 1024 / 1024 < 2; + if (!isLt2M) { + onError(new Error('图片大小不能超过2MB!')); + return; + } + + // 创建本地预览URL + const blobUrl = URL.createObjectURL(file); + + // 模拟上传成功响应 + setTimeout(() => { + onSuccess({ + status: 'done', + url: blobUrl, + message: blobUrl, + response: { + success: true, + message: '上传成功', + result: { + url: blobUrl + } + } + }); + }, 100); + } + }, + }, + { + label: '排序', + field: 'sortOrder', + component: 'InputNumber', + defaultValue: 0, + componentProps: { + min: 0, + placeholder: '请输入排序值', + }, + }, + { + label: '状态', + field: 'status', + component: 'JDictSelectTag', + defaultValue: '1', + componentProps: { + dictCode: 'valid_status', + placeholder: '请选择状态', + }, + }, + { + label: '描述', + field: 'description', + component: 'InputTextArea', + componentProps: { + rows: 3, + placeholder: '请输入分类描述', + }, + }, +]; \ No newline at end of file diff --git a/src/views/oroqen/product-category/OroqenProductCategoryList.vue b/src/views/oroqen/product-category/OroqenProductCategoryList.vue new file mode 100644 index 0000000..061f955 --- /dev/null +++ b/src/views/oroqen/product-category/OroqenProductCategoryList.vue @@ -0,0 +1,156 @@ + + + + + \ No newline at end of file diff --git a/src/views/oroqen/product-category/components/OroqenProductCategoryForm.vue b/src/views/oroqen/product-category/components/OroqenProductCategoryForm.vue new file mode 100644 index 0000000..6082036 --- /dev/null +++ b/src/views/oroqen/product-category/components/OroqenProductCategoryForm.vue @@ -0,0 +1,44 @@ + + + \ No newline at end of file diff --git a/src/views/oroqen/product-category/components/OroqenProductCategoryModal.vue b/src/views/oroqen/product-category/components/OroqenProductCategoryModal.vue new file mode 100644 index 0000000..c6aa82d --- /dev/null +++ b/src/views/oroqen/product-category/components/OroqenProductCategoryModal.vue @@ -0,0 +1,172 @@ + + + \ No newline at end of file