diff --git a/.env.development b/.env.development index 3055dfb..147d193 100644 --- a/.env.development +++ b/.env.development @@ -11,12 +11,14 @@ VITE_PUBLIC_PATH = / VITE_DROP_CONSOLE = false #后台接口父地址(必填) -VITE_GLOB_API_URL=https://xj-api.mcrm.vip:8888 +VITE_GLOB_API_URL=http://10.10.20.18 +#VITE_GLOB_API_URL=https://xj-api.mcrm.vip:8888 #VITE_GLOB_API_URL=http://192.168.1.223 #VITE_GLOB_API_URL=http://cqyt.test.yg.dt.io #后台接口全路径地址(必填) -VITE_GLOB_DOMAIN_URL=https://xj-api.mcrm.vip:8888 +VITE_GLOB_DOMAIN_URL=http://10.10.20.18 +#VITE_GLOB_DOMAIN_URL=https://xj-api.mcrm.vip:8888 #VITE_GLOB_DOMAIN_URL=http://192.168.1.223 #VITE_GLOB_DOMAIN_URL=http://cqyt.test.yg.dt.io # 接口前缀 diff --git a/src/views/check/check.api.ts b/src/views/check/check.api.ts new file mode 100644 index 0000000..ea0774a --- /dev/null +++ b/src/views/check/check.api.ts @@ -0,0 +1,15 @@ +import { defHttp } from '/@/utils/http/axios'; + +enum Api { + pendingList = '/health-emergency/emergency/firstAid/audit/pending', + passedList = '/health-emergency/emergency/firstAid/audit/passed', + rejectedList = '/health-emergency/emergency/firstAid/audit/rejected', + approve = '/health-emergency/emergency/firstAid/audit/approve', + reject = '/health-emergency/emergency/firstAid/audit/reject', +} + +export const pendingListApi = (params: any) => defHttp.get({ url: Api.pendingList, params }); +export const passedListApi = (params: any) => defHttp.get({ url: Api.passedList, params }); +export const rejectedListApi = (params: any) => defHttp.get({ url: Api.rejectedList, params }); +export const approveApi = (params: any) => defHttp.post({ url: Api.approve, params }); +export const rejectApi = (params: any) => defHttp.post({ url: Api.reject, params }); diff --git a/src/views/check/components/RejectReasonModal.vue b/src/views/check/components/RejectReasonModal.vue new file mode 100644 index 0000000..1cf816d --- /dev/null +++ b/src/views/check/components/RejectReasonModal.vue @@ -0,0 +1,43 @@ + + + diff --git a/src/views/check/index.vue b/src/views/check/index.vue new file mode 100644 index 0000000..45191a4 --- /dev/null +++ b/src/views/check/index.vue @@ -0,0 +1,308 @@ + + + + + diff --git a/src/views/label/index.vue b/src/views/label/index.vue new file mode 100644 index 0000000..d81778a --- /dev/null +++ b/src/views/label/index.vue @@ -0,0 +1,422 @@ + + + + + diff --git a/src/views/label/label.api.ts b/src/views/label/label.api.ts new file mode 100644 index 0000000..8474b51 --- /dev/null +++ b/src/views/label/label.api.ts @@ -0,0 +1,118 @@ +import { defHttp } from '/@/utils/http/axios'; +import { useMessage } from '/@/hooks/web/useMessage'; + +const { createConfirm } = useMessage(); + +enum Api { + // 分类 + categoryList = '/health-emergency/emergency/firstAid/category/list', + categoryListAll = '/health-emergency/emergency/firstAid/category/listAll', + categoryListRoot = '/health-emergency/emergency/firstAid/category/listRoot', + categoryListChildren = '/health-emergency/emergency/firstAid/category/listChildren', + categoryQueryById = '/health-emergency/emergency/firstAid/category/queryById', + categoryAdd = '/health-emergency/emergency/firstAid/category/add', + categoryEdit = '/health-emergency/emergency/firstAid/category/edit', + categoryDelete = '/health-emergency/emergency/firstAid/category/delete', + categoryDeleteBatch = '/health-emergency/emergency/firstAid/category/deleteBatch', + // 标签 + tagList = '/health-emergency/emergency/firstAid/tag/list', + tagListAll = '/health-emergency/emergency/firstAid/tag/listAll', + tagQueryById = '/health-emergency/emergency/firstAid/tag/queryById', + tagAdd = '/health-emergency/emergency/firstAid/tag/add', + tagEdit = '/health-emergency/emergency/firstAid/tag/edit', + tagDelete = '/health-emergency/emergency/firstAid/tag/delete', + tagDeleteBatch = '/health-emergency/emergency/firstAid/tag/deleteBatch', +} + +// ============ 分类 ============ +export const categoryListApi = (params: any) => defHttp.get({ url: Api.categoryList, params }); +export const categoryListAllApi = (params?: any) => defHttp.get({ url: Api.categoryListAll, params }); +export const categoryListRootApi = (params?: any) => defHttp.get({ url: Api.categoryListRoot, params }); +export const categoryListChildrenApi = (params: any) => defHttp.get({ url: Api.categoryListChildren, params }); +export const categoryQueryByIdApi = (params: any) => defHttp.get({ url: Api.categoryQueryById, params }); +export const categoryAddApi = (params: any) => defHttp.post({ url: Api.categoryAdd, params }); +export const categoryEditApi = (params: any) => defHttp.post({ url: Api.categoryEdit, params }); + +export const categoryDeleteApi = (params: any, handleSuccess: any) => { + createConfirm({ + iconType: 'warning', + title: '确认删除', + content: '是否删除该分类?', + onOk: async () => { + await defHttp.post({ url: Api.categoryDelete, params }); + handleSuccess(); + }, + }); +}; + +export const categoryDeleteBatchApi = (params: any, handleSuccess: any) => { + createConfirm({ + iconType: 'warning', + title: '批量删除', + content: `是否删除选中的 ${params?.length || 0} 个分类?`, + onOk: async () => { + await defHttp.post({ url: Api.categoryDeleteBatch, params }); + handleSuccess(); + }, + }); +}; + +// ============ 标签 ============ +export const tagListApi = (params: any) => defHttp.get({ url: Api.tagList, params }); +export const tagListAllApi = (params?: any) => defHttp.get({ url: Api.tagListAll, params }); +export const tagQueryByIdApi = (params: any) => defHttp.get({ url: Api.tagQueryById, params }); +export const tagAddApi = (params: any) => defHttp.post({ url: Api.tagAdd, params }); +export const tagEditApi = (params: any) => defHttp.post({ url: Api.tagEdit, params }); + +export const tagDeleteApi = (params: any, handleSuccess: any) => { + createConfirm({ + iconType: 'warning', + title: '确认删除', + content: '是否删除该标签?', + onOk: async () => { + await defHttp.post({ url: Api.tagDelete, params }); + handleSuccess(); + }, + }); +}; + +export const tagDeleteBatchApi = (params: any, handleSuccess: any) => { + createConfirm({ + iconType: 'warning', + title: '批量删除', + content: `是否删除选中的 ${params?.length || 0} 个标签?`, + onOk: async () => { + await defHttp.post({ url: Api.tagDeleteBatch, params }); + handleSuccess(); + }, + }); +}; + +// ============ 工具:扁平列表转树 ============ +export function buildTree(list: any[]): any[] { + const map = new Map(); + const roots: any[] = []; + list.forEach((item) => { + map.set(item.id, { ...item, children: [] }); + }); + list.forEach((item) => { + const node = map.get(item.id); + if (item.parentId && map.has(item.parentId)) { + map.get(item.parentId).children.push(node); + } else { + roots.push(node); + } + }); + // 移除空 children + const clean = (nodes: any[]) => { + nodes.forEach((n) => { + if (n.children.length === 0) { + delete n.children; + } else { + clean(n.children); + } + }); + return nodes; + }; + return clean(roots); +} diff --git a/src/views/resource/components/PreviewModal.vue b/src/views/resource/components/PreviewModal.vue new file mode 100644 index 0000000..e6cb690 --- /dev/null +++ b/src/views/resource/components/PreviewModal.vue @@ -0,0 +1,143 @@ + + + + + diff --git a/src/views/resource/components/ResourceFormModal.vue b/src/views/resource/components/ResourceFormModal.vue new file mode 100644 index 0000000..6d337cd --- /dev/null +++ b/src/views/resource/components/ResourceFormModal.vue @@ -0,0 +1,258 @@ + + + + + diff --git a/src/views/resource/components/VersionHistoryModal.vue b/src/views/resource/components/VersionHistoryModal.vue new file mode 100644 index 0000000..47c3f2c --- /dev/null +++ b/src/views/resource/components/VersionHistoryModal.vue @@ -0,0 +1,120 @@ + + + + + diff --git a/src/views/resource/index.vue b/src/views/resource/index.vue new file mode 100644 index 0000000..fb081a2 --- /dev/null +++ b/src/views/resource/index.vue @@ -0,0 +1,348 @@ + + + + + diff --git a/src/views/resource/resource.api.ts b/src/views/resource/resource.api.ts new file mode 100644 index 0000000..91ad1db --- /dev/null +++ b/src/views/resource/resource.api.ts @@ -0,0 +1,71 @@ +import { defHttp } from '/@/utils/http/axios'; +import { useMessage } from '/@/hooks/web/useMessage'; + +const { createConfirm } = useMessage(); + +enum Api { + // 资源 CRUD + list = '/health-emergency/emergency/firstAid/resource/list', + queryById = '/health-emergency/emergency/firstAid/resource/queryById', + add = '/health-emergency/emergency/firstAid/resource/add', + edit = '/health-emergency/emergency/firstAid/resource/edit', + delete = '/health-emergency/emergency/firstAid/resource/delete', + deleteBatch = '/health-emergency/emergency/firstAid/resource/deleteBatch', + submitForReview = '/health-emergency/emergency/firstAid/resource/submitForReview', + takeDown = '/health-emergency/emergency/firstAid/resource/takeDown', + publish = '/health-emergency/emergency/firstAid/resource/publish', + batchTakeDown = '/health-emergency/emergency/firstAid/resource/batchTakeDown', + batchPublish = '/health-emergency/emergency/firstAid/resource/batchPublish', + incrementView = '/health-emergency/emergency/firstAid/resource/incrementView', + copy = '/health-emergency/emergency/firstAid/resource/copy', + // 版本 + versionList = '/health-emergency/emergency/firstAid/version/list', + versionRollback = '/health-emergency/emergency/firstAid/version/rollback', + // 分类 & 标签(下拉用) + categoryListAll = '/health-emergency/emergency/firstAid/category/listAll', + tagListAll = '/health-emergency/emergency/firstAid/tag/listAll', +} + +export const listApi = (params: any) => defHttp.get({ url: Api.list, params }); +export const queryByIdApi = (params: any) => defHttp.get({ url: Api.queryById, params }); +export const addApi = (params: any) => defHttp.post({ url: Api.add, params }); +export const editApi = (params: any) => defHttp.post({ url: Api.edit, params }); +export const submitForReviewApi = (params: any) => defHttp.post({ url: Api.submitForReview, params }); +export const takeDownApi = (params: any) => defHttp.post({ url: Api.takeDown, params }); +export const publishApi = (params: any) => defHttp.post({ url: Api.publish, params }); +export const batchTakeDownApi = (params: any) => defHttp.post({ url: Api.batchTakeDown, params }); +export const batchPublishApi = (params: any) => defHttp.post({ url: Api.batchPublish, params }); +export const incrementViewApi = (params: any) => defHttp.post({ url: Api.incrementView, params }); +export const copyApi = (params: any) => defHttp.post({ url: Api.copy, params }); +export const versionListApi = (params: any) => defHttp.get({ url: Api.versionList, params }); +export const versionRollbackApi = (params: any) => defHttp.post({ url: Api.versionRollback, params }); +export const categoryListAllApi = (params?: any) => defHttp.get({ url: Api.categoryListAll, params }); +export const tagListAllApi = (params?: any) => defHttp.get({ url: Api.tagListAll, params }); + +export const deleteApi = (params: any, handleSuccess: any) => { + createConfirm({ + iconType: 'warning', + title: '确认删除', + content: '是否将选中资源移入回收站?', + okText: '确认', + cancelText: '取消', + onOk: async () => { + await defHttp.post({ url: Api.delete, params }); + handleSuccess(); + }, + }); +}; + +export const batchDeleteApi = (params: any, handleSuccess: any) => { + createConfirm({ + iconType: 'warning', + title: '批量删除', + content: `是否将选中的 ${params?.length || 0} 条资源移入回收站?`, + okText: '确认', + cancelText: '取消', + onOk: async () => { + await defHttp.post({ url: Api.deleteBatch, params }); + handleSuccess(); + }, + }); +}; diff --git a/src/views/resource/resource.data.ts b/src/views/resource/resource.data.ts new file mode 100644 index 0000000..0ef4955 --- /dev/null +++ b/src/views/resource/resource.data.ts @@ -0,0 +1,166 @@ +import { BasicColumn, FormSchema } from '/@/components/Table'; + +// 发布状态 +export const STATUS = { + DRAFT: 0, + PUBLISHED: 1, + OFFLINE: 2, +}; + +// 审核状态 +export const AUDIT_STATUS = { + PENDING: 10, + PASSED: 11, + REJECTED: 12, +}; + +// 复合状态(搜索用) +export const COMBINED_STATUS = { + DRAFT: '0', + PUBLISHED: '1', + OFFLINE: '2', + PENDING: '10', + PASSED: '11', + REJECTED: '12', +}; + +// 内容类型 +export const CONTENT_TYPE = { + IMAGE_TEXT: { label: '图文', color: 'orange', icon: '📄' }, + VIDEO: { label: '视频', color: 'purple', icon: '🎬' }, + AUDIO: { label: '音频', color: 'green', icon: '🎧' }, + PDF: { label: 'PDF', color: 'red', icon: '📑' }, +}; + +// 根据发布状态+审核状态返回展示信息 +export function getResourceDisplayStatus(status: number, auditStatus: number | null) { + if (status === STATUS.PUBLISHED) return { text: '已发布', color: 'success' }; + if (status === STATUS.OFFLINE) return { text: '已下架', color: 'error' }; + if (auditStatus === AUDIT_STATUS.PENDING) return { text: '待审核', color: 'warning' }; + if (auditStatus === AUDIT_STATUS.REJECTED) return { text: '已驳回', color: 'error' }; + return { text: '草稿', color: 'default' }; +} + +// 内容类型选项 +export const TYPE_OPTIONS = [ + { label: '图文', value: 'IMAGE_TEXT' }, + { label: '视频', value: 'VIDEO' }, + { label: '音频', value: 'AUDIO' }, + { label: 'PDF', value: 'PDF' }, +]; + +// 复合状态选项 +export const STATUS_OPTIONS = [ + { label: '草稿', value: '0' }, + { label: '已发布', value: '1' }, + { label: '已下架', value: '2' }, + { label: '待审核', value: '10' }, + { label: '已通过', value: '11' }, + { label: '已驳回', value: '12' }, +]; + +// 适用场景 +export const SCENE_OPTIONS = [ + { label: '油田现场', value: '油田现场' }, + { label: '日常生活', value: '日常生活' }, + { label: '高原环境', value: '高原环境' }, + { label: '高温环境', value: '高温环境' }, +]; + +// 表格列定义 +export const columns: BasicColumn[] = [ + { + title: '封面', + dataIndex: 'coverImage', + width: 80, + align: 'center', + }, + { + title: '标题', + dataIndex: 'title', + align: 'left', + }, + { + title: '分类', + dataIndex: 'categoryName', + width: 100, + align: 'center', + }, + { + title: '类型', + dataIndex: 'contentType', + width: 90, + align: 'center', + }, + { + title: '标签', + dataIndex: 'tagNameList', + width: 160, + align: 'left', + }, + { + title: '状态', + dataIndex: 'statusDisplay', + width: 100, + align: 'center', + }, + { + title: '阅读/收藏', + dataIndex: 'viewFavorite', + width: 110, + align: 'center', + }, + { + title: '创建时间', + dataIndex: 'createTime', + width: 170, + align: 'center', + }, +]; + +// 搜索表单 +export const searchSchema: FormSchema[] = [ + { + field: 'title', + label: '标题', + component: 'Input', + componentProps: { + placeholder: '搜索标题', + }, + colProps: { span: 6 }, + }, + { + field: 'categoryId', + label: '分类', + component: 'ApiSelect', + componentProps: { + api: () => import('./resource.api').then((m) => m.categoryListAllApi()), + labelField: 'name', + valueField: 'id', + placeholder: '全部分类', + }, + colProps: { span: 6 }, + }, + { + field: 'combinedStatus', + label: '状态', + component: 'Select', + componentProps: { + options: STATUS_OPTIONS, + placeholder: '全部状态', + allowClear: true, + }, + colProps: { span: 6 }, + }, + { + field: 'contentType', + label: '类型', + component: 'Select', + componentProps: { + options: TYPE_OPTIONS, + placeholder: '全部类型', + allowClear: true, + }, + colProps: { span: 6 }, + }, +];