diff --git a/src/api/ops/assetCategory.ts b/src/api/ops/assetCategory.ts index a051cf0..6ed0056 100644 --- a/src/api/ops/assetCategory.ts +++ b/src/api/ops/assetCategory.ts @@ -1,46 +1,92 @@ -import { request } from "@/api/request"; +import { request } from '@/api/request' + +/** 资产分类数据类型 */ +export interface AssetCategory { + id: number + name: string + code: string + description?: string + icon?: string + color?: string + parent_id?: number + parent?: AssetCategory + level: number + path?: string + enabled: boolean + sort: number + asset_count: number + remarks?: string + created_by?: string + updated_by?: string + created_at?: string + updated_at?: string + children?: AssetCategory[] +} + +/** 分页列表参数 */ +export interface CategoryListParams { + page?: number + page_size?: number + sort?: string + order?: 'asc' | 'desc' + keyword?: string +} + +/** 创建/更新分类参数 */ +export interface CategoryFormData { + id?: number + name: string + code: string + description?: string + icon?: string + color?: string + parent_id?: number | null + enabled?: boolean + sort?: number + remarks?: string +} /** 获取资产分类列表(分页) */ -export const fetchCategoryList = (data?: { - page?: number; - page_size?: number; - keyword?: string; - parent_id?: number; -}) => { - return request.post("/Assets/v1/category/list", data || {}); -}; +export const fetchCategoryList = (params?: CategoryListParams) => { + return request.post('/Assets/v1/category/list', params || {}) +} /** 获取资产分类详情 */ export const fetchCategoryDetail = (id: number) => { - return request.get(`/Assets/v1/category/detail/${id}`); -}; + return request.get(`/Assets/v1/category/detail/${id}`) +} /** 创建资产分类 */ -export const createCategory = (data: any) => { - return request.post("/Assets/v1/category/create", data); -}; +export const createCategory = (data: CategoryFormData) => { + return request.post('/Assets/v1/category/create', data) +} /** 更新资产分类 */ -export const updateCategory = (data: any) => { - return request.put("/Assets/v1/category/update", data); -}; +export const updateCategory = (data: CategoryFormData) => { + return request.put('/Assets/v1/category/update', data) +} /** 删除资产分类 */ export const deleteCategory = (id: number) => { - return request.delete(`/Assets/v1/category/delete/${id}`); -}; + return request.delete(`/Assets/v1/category/delete/${id}`) +} /** 获取所有资产分类(用于下拉选择) */ -export const fetchAllCategories = () => { - return request.get("/Assets/v1/category/all"); -}; +export const fetchAllCategories = (keyword?: string) => { + return request.get('/Assets/v1/category/all', { params: { keyword } }) +} /** 获取资产分类树形结构 */ -export const fetchCategoryTree = () => { - return request.get("/Assets/v1/category/tree"); -}; +export const fetchCategoryTree = (keyword?: string) => { + return request.get('/Assets/v1/category/tree', { params: { keyword } }) +} /** 获取指定分类的子分类列表 */ export const fetchCategoryChildren = (id: number) => { - return request.get(`/Assets/v1/category/children/${id}`); -}; + return request.get(`/Assets/v1/category/children/${id}`) +} + +/** 根据父级分类ID获取分类列表 */ +export const fetchCategoryByParent = (parentId: number) => { + return request.get(`/Assets/v1/category/parent/${parentId}`) +} diff --git a/src/api/ops/supplier.ts b/src/api/ops/supplier.ts index 9f05e8a..2b8b92b 100644 --- a/src/api/ops/supplier.ts +++ b/src/api/ops/supplier.ts @@ -32,9 +32,10 @@ export const deleteSupplier = (id: number) => { }; /** 获取所有供应商(用于下拉选择) */ -export const fetchAllSuppliers = (keyword?: string, status?: string) => { +export const fetchAllSuppliers = (keyword?: string, status?: string, pageSize?: number) => { const params: any = {}; if (keyword) params.keyword = keyword; if (status) params.status = status; + if (pageSize) params.page_size = pageSize; return request.get("/Assets/v1/supplier/all", { params }); }; \ No newline at end of file diff --git a/src/router/routes/modules/ops.ts b/src/router/routes/modules/ops.ts index 6b1f40d..e97f4f6 100644 --- a/src/router/routes/modules/ops.ts +++ b/src/router/routes/modules/ops.ts @@ -96,7 +96,7 @@ const OPS: AppRouteRecordRaw = { // { // path: 'assets/device', // name: 'AssetsDevice', - // component: () => import('@/views/ops/pages/assets/device/index.vue'), + // component: () => import('@/views/ops/pages/assets/device/list/index.vue'), // meta: { // locale: '设备管理', // requiresAuth: true, @@ -104,9 +104,20 @@ const OPS: AppRouteRecordRaw = { // }, // }, // { + // path: 'assets/device/form', + // name: 'AssetsDeviceForm', + // component: () => import('@/views/ops/pages/assets/device/form/index.vue'), + // meta: { + // locale: '新增/编辑设备', + // requiresAuth: true, + // roles: ['*'], + // hideInMenu: true, + // }, + // }, + // { // path: 'assets/supplier', // name: 'AssetsSupplier', - // component: () => import('@/views/ops/pages/assets/supplier/index.vue'), + // component: () => import('@/views/ops/pages/assets/supplier/list/index.vue'), // meta: { // locale: '供应商管理', // requiresAuth: true, @@ -114,6 +125,17 @@ const OPS: AppRouteRecordRaw = { // }, // }, // { + // path: 'assets/supplier/form', + // name: 'AssetsSupplierForm', + // component: () => import('@/views/ops/pages/assets/supplier/form/index.vue'), + // meta: { + // locale: '新增/编辑供应商', + // requiresAuth: true, + // roles: ['*'], + // hideInMenu: true, + // }, + // }, + // { // path: 'assets/classify', // name: 'AssetsClassify', // component: () => import('@/views/ops/pages/assets/classify/index.vue'), diff --git a/src/views/help/index.vue b/src/views/help/index.vue index e6427e5..d85b17b 100644 --- a/src/views/help/index.vue +++ b/src/views/help/index.vue @@ -21,8 +21,8 @@ - - - - -
-

- - 操作手册 -

- -
-
-
- +
+ 点击查看详情 →
-
-

{{ manual.title }}

-

{{ manual.description }}

-
- 格式:{{ manual.format }} - 大小:{{ manual.size }} - 更新:{{ manual.updatedAt }} -
-
- - 下载 -
@@ -172,9 +147,9 @@
-

电话联系

+

技术支持热线

工作日 9:00-18:00

-

400-XXX-XXXX

+

400-888-8888

@@ -185,7 +160,7 @@

邮件咨询

我们会在 24 小时内回复

-

support@example.com

+

david.yan@qq.com

@@ -213,25 +188,57 @@

© 2026 智能运维管理系统。All rights reserved.

+ + + +
+
+
+ {{ currentGuide?.categoryName }} + 更新时间:{{ currentGuide?.updatedAt }} +
+
+
+
+
+

{{ section.title }}

+

{{ section.text }}

+
    +
  • {{ item }}
  • +
+
+
+
+ +
+
+
+
+ \ No newline at end of file diff --git a/src/views/ops/pages/assets/classify/components/CategoryFormDialog.vue b/src/views/ops/pages/assets/classify/components/CategoryFormDialog.vue index b716e74..c03a8c5 100644 --- a/src/views/ops/pages/assets/classify/components/CategoryFormDialog.vue +++ b/src/views/ops/pages/assets/classify/components/CategoryFormDialog.vue @@ -1,137 +1,96 @@ @@ -307,79 +275,4 @@ const handleVisibleChange = (visible: boolean) => { export default { name: 'CategoryFormDialog', } - - - + \ No newline at end of file diff --git a/src/views/ops/pages/assets/classify/config/columns.ts b/src/views/ops/pages/assets/classify/config/columns.ts new file mode 100644 index 0000000..896bf9d --- /dev/null +++ b/src/views/ops/pages/assets/classify/config/columns.ts @@ -0,0 +1,69 @@ +import type { TableColumnData } from '@arco-design/web-vue/es/table/interface' + +export const columns: TableColumnData[] = [ + { + title: '序号', + dataIndex: 'index', + slotName: 'index', + width: 80, + }, + { + title: '分类名称', + dataIndex: 'name', + width: 180, + }, + { + title: '分类编码', + dataIndex: 'code', + width: 150, + }, + { + title: '层级', + dataIndex: 'level', + slotName: 'level', + width: 80, + }, + { + title: '父级分类', + dataIndex: 'parent', + slotName: 'parent', + width: 150, + }, + { + title: '资产数量', + dataIndex: 'asset_count', + slotName: 'asset_count', + width: 100, + }, + { + title: '排序', + dataIndex: 'sort', + width: 80, + }, + { + title: '状态', + dataIndex: 'enabled', + slotName: 'enabled', + width: 100, + }, + { + title: '描述', + dataIndex: 'description', + ellipsis: true, + tooltip: true, + width: 200, + }, + { + title: '创建时间', + dataIndex: 'created_at', + slotName: 'created_at', + width: 180, + }, + { + title: '操作', + dataIndex: 'actions', + slotName: 'actions', + width: 320, + fixed: 'right' as const, + }, +] \ No newline at end of file diff --git a/src/views/ops/pages/assets/classify/config/search-form.ts b/src/views/ops/pages/assets/classify/config/search-form.ts new file mode 100644 index 0000000..048bad5 --- /dev/null +++ b/src/views/ops/pages/assets/classify/config/search-form.ts @@ -0,0 +1,10 @@ +import type { FormItem } from '@/components/search-form/types' + +export const searchFormConfig: FormItem[] = [ + { + field: 'keyword', + label: '关键词', + type: 'input', + placeholder: '请输入分类名称或编码', + }, +] \ No newline at end of file diff --git a/src/views/ops/pages/assets/classify/index.vue b/src/views/ops/pages/assets/classify/index.vue index b99c778..e20cc94 100644 --- a/src/views/ops/pages/assets/classify/index.vue +++ b/src/views/ops/pages/assets/classify/index.vue @@ -18,7 +18,10 @@ > @@ -27,29 +30,35 @@ {{ rowIndex + 1 + (pagination.current - 1) * pagination.pageSize }} + + + - - @@ -91,21 +102,21 @@ import { Message, Modal } from '@arco-design/web-vue' import { IconPlus } from '@arco-design/web-vue/es/icon' import type { FormItem } from '@/components/search-form/types' import SearchTable from '@/components/search-table/index.vue' +import { searchFormConfig } from './config/search-form' +import { columns as columnsConfig } from './config/columns' import { fetchCategoryList, deleteCategory, - fetchAllCategories, - fetchCategoryDetail, } from '@/api/ops/assetCategory' +import type { AssetCategory } from '@/api/ops/assetCategory' import CategoryFormDialog from './components/CategoryFormDialog.vue' import CategoryDetailDialog from './components/CategoryDetailDialog.vue' // 状态管理 const loading = ref(false) -const tableData = ref([]) +const tableData = ref([]) const formModel = ref({ keyword: '', - parent_id: '', }) const pagination = reactive({ @@ -114,114 +125,46 @@ const pagination = reactive({ total: 0, }) -// 父级分类列表(用于下拉选择) -const parentCategories = ref([]) - // 表单项配置 -const formItems = computed(() => [ - { - field: 'keyword', - label: '关键词', - type: 'input', - placeholder: '请输入分类名称或编码', - }, - { - field: 'parent_id', - label: '父级分类', - type: 'select', - placeholder: '请选择父级分类', - options: parentCategories.value.map((item) => ({ - label: item.name, - value: item.id, - })), - allowClear: true, - allowSearch: true, - }, -]) +const formItems = computed(() => searchFormConfig) // 表格列配置 -const columns = computed(() => [ - { - title: '序号', - dataIndex: 'index', - slotName: 'index', - width: 80, - align: 'center' as const, - }, - { - title: '分类名称', - dataIndex: 'name', - ellipsis: true, - tooltip: true, - }, - { - title: '分类编码', - dataIndex: 'code', - ellipsis: true, - tooltip: true, - }, - { - title: '父级分类', - dataIndex: 'parent', - slotName: 'parent', - ellipsis: true, - tooltip: true, - }, - { - title: '层级', - dataIndex: 'level', - width: 80, - align: 'center' as const, - }, - { - title: '排序', - dataIndex: 'sort', - width: 80, - align: 'center' as const, - }, - { - title: '颜色标识', - dataIndex: 'color', - slotName: 'color', - width: 120, - align: 'center' as const, - }, - { - title: '是否启用', - dataIndex: 'enabled', - slotName: 'enabled', - width: 100, - align: 'center' as const, - }, - { - title: '操作', - slotName: 'actions', - width: 300, - fixed: 'right' as const, - }, -]) +const columns = computed(() => columnsConfig) // 当前选中的分类 -const currentCategory = ref(null) -const editingCategory = ref(null) +const currentCategoryId = ref(undefined) +const editingCategory = ref(null) // 对话框可见性 const formVisible = ref(false) const detailVisible = ref(false) -// 固定的父级分类ID(用于新增子分类时) -const fixedParentId = ref(undefined) +// 获取层级颜色 +const getLevelColor = (level: number) => { + const colors: Record = { + 1: 'blue', + 2: 'green', + 3: 'orange', + 4: 'purple', + 5: 'cyan', + } + return colors[level] || 'gray' +} -// 是否显示父级分类选择器 -const showParentSelector = ref(true) - -// 获取父级分类列表(用于下拉选择) -const fetchParentCategories = async () => { +// 格式化日期时间 +const formatDateTime = (dateStr?: string) => { + if (!dateStr) return '-' try { - const res = await fetchAllCategories() - parentCategories.value = res.details || [] - } catch (error) { - console.error('获取父级分类列表失败:', error) + const date = new Date(dateStr) + return date.toLocaleString('zh-CN', { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + }) + } catch { + return dateStr } } @@ -230,11 +173,10 @@ const fetchCategories = async () => { loading.value = true try { - const params: any = { + const params = { page: pagination.current, page_size: pagination.pageSize, keyword: formModel.value.keyword || undefined, - parent_id: formModel.value.parent_id || undefined, } const res = await fetchCategoryList(params) @@ -266,7 +208,6 @@ const handleFormModelUpdate = (value: any) => { const handleReset = () => { formModel.value = { keyword: '', - parent_id: '', } pagination.current = 1 fetchCategories() @@ -284,53 +225,38 @@ const handleRefresh = () => { Message.success('数据已刷新') } -// 新增分类 +// 新建分类 const handleCreate = () => { editingCategory.value = null - fixedParentId.value = undefined - showParentSelector.value = false - formVisible.value = true -} - -// 新增子分类 -const handleAddChild = (record: any) => { - editingCategory.value = null - fixedParentId.value = record.id - showParentSelector.value = true formVisible.value = true } // 编辑分类 -const handleEdit = (record: any) => { - console.log('编辑分类:', record) +const handleEdit = (record: AssetCategory) => { editingCategory.value = record formVisible.value = true } +// 添加子分类 +const handleAddChild = (record: AssetCategory) => { + editingCategory.value = { + parent_id: record.id, + } as AssetCategory + formVisible.value = true +} + // 详情 -const handleDetail = async (record: any) => { - console.log('查看详情:', record) - try { - const res = await fetchCategoryDetail(record.id) - if (res.code === 0) { - currentCategory.value = res.details - detailVisible.value = true - } else { - Message.error(res.message || '获取详情失败') - } - } catch (error) { - console.error('获取分类详情失败:', error) - Message.error('获取详情失败') - } +const handleDetail = (record: AssetCategory) => { + currentCategoryId.value = record.id + detailVisible.value = true } // 删除分类 -const handleDelete = async (record: any) => { - console.log('删除分类:', record) +const handleDelete = async (record: AssetCategory) => { try { Modal.confirm({ title: '确认删除', - content: `确认删除分类 ${record.name} 吗?`, + content: `确认删除分类「${record.name}」吗?如果该分类下存在子分类或资产,将无法删除。`, onOk: async () => { const res = await deleteCategory(record.id) if (res.code === 0) { @@ -348,21 +274,18 @@ const handleDelete = async (record: any) => { // 表单成功回调 const handleFormSuccess = () => { - formVisible.value = false fetchCategories() - fetchParentCategories() } // 初始化加载数据 onMounted(() => { - fetchParentCategories() fetchCategories() }) @@ -370,18 +293,4 @@ export default { .container { margin-top: 20px; } - -.color-cell { - display: flex; - align-items: center; - justify-content: center; - gap: 8px; - - .color-block { - width: 20px; - height: 20px; - border-radius: 4px; - border: 1px solid #d9d9d9; - } -} - + \ No newline at end of file diff --git a/src/views/ops/pages/assets/device/components/DeviceFormDialog.vue b/src/views/ops/pages/assets/device/components/DeviceFormDialog.vue deleted file mode 100644 index e48bb2e..0000000 --- a/src/views/ops/pages/assets/device/components/DeviceFormDialog.vue +++ /dev/null @@ -1,687 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/views/ops/pages/assets/device/form/index.vue b/src/views/ops/pages/assets/device/form/index.vue new file mode 100644 index 0000000..dae5ca4 --- /dev/null +++ b/src/views/ops/pages/assets/device/form/index.vue @@ -0,0 +1,794 @@ + + + + + + + \ No newline at end of file diff --git a/src/views/ops/pages/assets/device/index.vue b/src/views/ops/pages/assets/device/list/index.vue similarity index 91% rename from src/views/ops/pages/assets/device/index.vue rename to src/views/ops/pages/assets/device/list/index.vue index e345a1e..23f6898 100644 --- a/src/views/ops/pages/assets/device/index.vue +++ b/src/views/ops/pages/assets/device/list/index.vue @@ -20,9 +20,6 @@ 新增设备 - - 导出 - @@ -66,13 +63,6 @@ - - - import { ref, reactive, computed, onMounted } from 'vue' +import { useRouter } from 'vue-router' import { Message, Modal } from '@arco-design/web-vue' import type { FormItem } from '@/components/search-form/types' import SearchTable from '@/components/search-table/index.vue' @@ -94,8 +85,9 @@ import { getAssetStatusColor, assetStatusOptions, } from '@/api/ops/asset' -import DeviceFormDialog from './components/DeviceFormDialog.vue' -import DeviceDetailDialog from './components/DeviceDetailDialog.vue' +import DeviceDetailDialog from '../components/DeviceDetailDialog.vue' + +const router = useRouter() // 状态管理 const loading = ref(false) @@ -204,17 +196,15 @@ const columns = computed(() => [ { title: '操作', slotName: 'actions', - width: 280, + width: 220, fixed: 'right' as const, }, ]) // 当前选中的设备 const currentDevice = ref(null) -const editingDevice = ref(null) // 对话框可见性 -const formVisible = ref(false) const detailVisible = ref(false) // 获取设备列表 @@ -276,16 +266,17 @@ const handleRefresh = () => { Message.success('数据已刷新') } -// 新增设备 +// 新增设备 - 跳转到新增页面 const handleCreate = () => { - editingDevice.value = null - formVisible.value = true + router.push('/assets/device/form') } -// 编辑设备 +// 编辑设备 - 跳转到编辑页面 const handleEdit = (record: any) => { - editingDevice.value = record - formVisible.value = true + router.push({ + path: '/assets/device/form', + query: { id: record.id }, + }) } // 详情 @@ -335,7 +326,7 @@ const handleExport = async () => { keyword: formModel.value.keyword || undefined, status: formModel.value.status || undefined, }) - + if (res.code === 0 && res.details?.data) { const data = res.details.data const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }) @@ -353,12 +344,6 @@ const handleExport = async () => { } } -// 表单成功回调 -const handleFormSuccess = () => { - formVisible.value = false - fetchDevices() -} - // 格式化金额 const formatMoney = (value: number | string | null | undefined) => { if (value === null || value === undefined || value === '') return '-' @@ -389,7 +374,7 @@ onMounted(() => { diff --git a/src/views/ops/pages/assets/supplier/components/SupplierFormDialog.vue b/src/views/ops/pages/assets/supplier/components/SupplierFormDialog.vue deleted file mode 100644 index b071012..0000000 --- a/src/views/ops/pages/assets/supplier/components/SupplierFormDialog.vue +++ /dev/null @@ -1,464 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/src/views/ops/pages/assets/supplier/form/index.vue b/src/views/ops/pages/assets/supplier/form/index.vue new file mode 100644 index 0000000..7c95511 --- /dev/null +++ b/src/views/ops/pages/assets/supplier/form/index.vue @@ -0,0 +1,490 @@ + + + + + + + \ No newline at end of file diff --git a/src/views/ops/pages/assets/supplier/index.vue b/src/views/ops/pages/assets/supplier/list/index.vue similarity index 92% rename from src/views/ops/pages/assets/supplier/index.vue rename to src/views/ops/pages/assets/supplier/list/index.vue index 36c6643..0fac2c6 100644 --- a/src/views/ops/pages/assets/supplier/index.vue +++ b/src/views/ops/pages/assets/supplier/list/index.vue @@ -58,13 +58,6 @@ - - - import { ref, reactive, computed, onMounted } from 'vue' +import { useRouter } from 'vue-router' import { Message, Modal } from '@arco-design/web-vue' import type { FormItem } from '@/components/search-form/types' import SearchTable from '@/components/search-table/index.vue' @@ -83,8 +77,9 @@ import { deleteSupplier, fetchSupplierDetail, } from '@/api/ops/supplier' -import SupplierFormDialog from './components/SupplierFormDialog.vue' -import SupplierDetailDialog from './components/SupplierDetailDialog.vue' +import SupplierDetailDialog from '../components/SupplierDetailDialog.vue' + +const router = useRouter() // 状态选项 const statusOptions = [ @@ -200,10 +195,8 @@ const columns = computed(() => [ // 当前选中的供应商 const currentSupplier = ref(null) -const editingSupplier = ref(null) // 对话框可见性 -const formVisible = ref(false) const detailVisible = ref(false) // 获取供应商列表 @@ -265,16 +258,17 @@ const handleRefresh = () => { Message.success('数据已刷新') } -// 新增供应商 +// 新增供应商 - 跳转到新增页面 const handleCreate = () => { - editingSupplier.value = null - formVisible.value = true + router.push('/assets/supplier/form') } -// 编辑供应商 +// 编辑供应商 - 跳转到编辑页面(通过 query 参数传递 id) const handleEdit = (record: any) => { - editingSupplier.value = record - formVisible.value = true + router.push({ + path: '/assets/supplier/form', + query: { id: record.id }, + }) } // 详情 @@ -314,12 +308,6 @@ const handleDelete = async (record: any) => { } } -// 表单成功回调 -const handleFormSuccess = () => { - formVisible.value = false - fetchSuppliers() -} - // 获取状态颜色 const getStatusColor = (status: string) => { const colorMap: Record = { @@ -373,7 +361,7 @@ onMounted(() => { diff --git a/src/views/ops/pages/kb/review/index.vue b/src/views/ops/pages/kb/review/index.vue index 65b2c09..757457b 100644 --- a/src/views/ops/pages/kb/review/index.vue +++ b/src/views/ops/pages/kb/review/index.vue @@ -146,7 +146,7 @@