diff --git a/commitlint.config.js b/commitlint.config.js index b21d451..24c75aa 100644 --- a/commitlint.config.js +++ b/commitlint.config.js @@ -1,6 +1,7 @@ -// commit-lint config +/** 继承 Conventional Commits 格式,并限制仓库允许的提交类型。 */ export default { extends: ['@commitlint/config-conventional'], + /** 提交类型白名单;新增类别时需同步更新此数组。 */ rules: { 'type-enum': [ 2, diff --git a/eslint.config.js b/eslint.config.js index 401f45c..ced473e 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -6,6 +6,7 @@ import vueCss from 'eslint-plugin-vue-scoped-css'; import globals from 'globals'; import typescript from 'typescript-eslint'; +/** 组合 Antfu 基础规则与本项目 Vue、样式和导入排序约束。 */ export default antfu( { typescript: true, @@ -19,6 +20,7 @@ export default antfu( ...vueCss.configs['flat/recommended'], prettier, { + // 为浏览器、Node 和 Vue 单文件组件脚本补充全局变量及解析器。 languageOptions: { globals: { ...globals.browser, @@ -48,6 +50,7 @@ export default antfu( 'import/extensions': ['.js', '.jsx', '.ts', '.tsx'], }, + // 项目规则覆盖:允许现有模板写法,并统一采用 simple-import-sort。 rules: { /* Closed due to template running * (Recommended to open!) @@ -97,6 +100,7 @@ export default antfu( }, }, { + // Vue 模板专属的组件命名、块顺序和 scoped 样式约束。 files: ['**/*.vue'], rules: { @@ -131,6 +135,7 @@ export default antfu( 'vue/padding-line-between-blocks': ['error', 'never'], }, }, + // 排除依赖、生成产物和不参与常规 lint 的辅助目录。 globalIgnores([ '**/snapshot*', '**/dist', diff --git a/index.html b/index.html index 587b9b1..196434c 100644 --- a/index.html +++ b/index.html @@ -1,4 +1,4 @@ - + @@ -9,16 +9,8 @@
- - + diff --git a/mock/index.ts b/mock/index.ts index 916c23f..54c7181 100644 --- a/mock/index.ts +++ b/mock/index.ts @@ -1,8 +1,10 @@ import Mock from 'mockjs'; import type { MockMethod } from 'vite-plugin-mock'; +/** 本地开发用接口集合,统一返回业务 code/data 结构以模拟后端响应。 */ export default [ { + /** 采购记录列表接口,生成随机数量、管理员和采购产品信息。 */ url: '/api/get-purchase-list', method: 'get', response: () => ({ @@ -33,6 +35,7 @@ export default [ }), }, { + /** 合同基础列表接口,生成状态、金额、收付类型和更新时间等字段。 */ url: '/api/get-list', method: 'get', response: () => ({ @@ -57,6 +60,7 @@ export default [ }), }, { + /** 详情页基础资料接口,返回账户、权限、语言和时区等展示字段。 */ url: '/api/detail-basic', method: 'get', response: () => ({ @@ -75,6 +79,7 @@ export default [ }), }, { + /** 卡片列表接口,随机组合产品名称、图片、类型和说明文案。 */ url: '/api/get-card-list', method: 'get', response: () => ({ @@ -108,6 +113,7 @@ export default [ }), }, { + /** 项目列表接口,生成项目名称及其管理员联系信息。 */ url: '/api/get-project-list', method: 'get', response: () => ({ @@ -134,6 +140,7 @@ export default [ }), }, { + /** 通用 POST 示例接口,固定延迟后返回成功状态和示例名称。 */ url: '/api/post', method: 'post', timeout: 2000, @@ -145,6 +152,7 @@ export default [ }, }, { + /** 菜单接口,提供列表、表单、详情和 iframe 路由的嵌套样例。 */ url: '/api/get-menu-list-i18n', method: 'get', timeout: 2000, diff --git a/src/App.vue b/src/App.vue index b291f91..5586d8a 100644 --- a/src/App.vue +++ b/src/App.vue @@ -11,6 +11,7 @@ import { useSettingStore } from '@/store'; const store = useSettingStore(); +/** 将设置 store 当前解析出的明暗主题提供给根路由视图。 */ const mode = computed(() => { return store.displayMode; }); diff --git a/src/api/detail.ts b/src/api/detail.ts index 858c7ff..d3033a1 100644 --- a/src/api/detail.ts +++ b/src/api/detail.ts @@ -2,16 +2,20 @@ import type { ProjectListResult, PurchaseListResult } from '@/api/model/detailMo import { request } from '@/utils/request'; const Api = { + /** 采购记录列表接口地址。 */ PurchaseList: '/get-purchase-list', + /** 项目列表接口地址。 */ ProjectList: '/get-project-list', }; +/** 获取详情页展示的采购记录。 */ export function getPurchaseList() { return request.get({ url: Api.PurchaseList, }); } +/** 获取详情页展示的项目记录。 */ export function getProjectList() { return request.get({ url: Api.ProjectList, diff --git a/src/api/list.ts b/src/api/list.ts index ab30e2b..daf051c 100644 --- a/src/api/list.ts +++ b/src/api/list.ts @@ -2,16 +2,20 @@ import type { CardListResult, ListResult } from '@/api/model/listModel'; import { request } from '@/utils/request'; const Api = { + /** 基础列表数据接口地址。 */ BaseList: '/get-list', + /** 卡片列表数据接口地址。 */ CardList: '/get-card-list', }; +/** 获取基础列表页所需的数据集合。 */ export function getList() { return request.get({ url: Api.BaseList, }); } +/** 获取卡片列表页所需的数据集合。 */ export function getCardList() { return request.get({ url: Api.CardList, diff --git a/src/api/model/detailModel.ts b/src/api/model/detailModel.ts index c144b48..5854af7 100644 --- a/src/api/model/detailModel.ts +++ b/src/api/model/detailModel.ts @@ -1,23 +1,43 @@ +/** 采购记录列表接口的响应结构。 */ export interface PurchaseListResult { + /** 接口返回的采购记录。 */ list: Array; } + +/** 采购列表中的单条采购记录。 */ export interface PurchaseInfo { + /** 负责该采购记录的管理员名称。 */ adminName: string; + /** 记录在列表或业务系统中的索引标识。 */ index: string; + /** 采购产品名称。 */ pdName: string; + /** 采购产品编号。 */ pdNum: string; + /** 采购产品类型。 */ pdType: string; + /** 采购数量。 */ purchaseNum: number; + /** 采购记录最近更新时间。 */ updateTime: Date; } +/** 项目列表接口的响应结构。 */ export interface ProjectListResult { + /** 接口返回的项目记录。 */ list: Array; } + +/** 项目列表中的单个项目数据。 */ export interface ProjectInfo { + /** 项目管理员名称。 */ adminName: string; + /** 项目管理员联系电话。 */ adminPhone: string; + /** 列表中的序号或索引值。 */ index: number; + /** 项目名称。 */ name: string; + /** 项目最近更新时间。 */ updateTime: Date; } diff --git a/src/api/model/listModel.ts b/src/api/model/listModel.ts index 453114d..1d4a982 100644 --- a/src/api/model/listModel.ts +++ b/src/api/model/listModel.ts @@ -1,26 +1,49 @@ +/** 基础列表接口的响应结构。 */ export interface ListResult { + /** 接口返回的基础列表记录。 */ list: Array; } + +/** 基础列表中单条记录的字段定义。 */ export interface ListModel { + /** 负责该记录的管理员名称。 */ adminName: string; + /** 记录对应的金额文本。 */ amount: string; + /** 合同类型对应的业务编码。 */ contractType: number; + /** 列表中的序号或索引值。 */ index: number; + /** 记录名称。 */ name: string; + /** 记录编号。 */ no: string; + /** 支付方式对应的业务编码。 */ paymentType: number; + /** 记录状态对应的业务编码。 */ status: number; + /** 记录最近更新时间。 */ updateTime: Date; } +/** 卡片列表接口的响应结构。 */ export interface CardListResult { + /** 接口返回的卡片记录。 */ list: Array; } + +/** 卡片列表中单张卡片的数据字段。 */ export interface CardList { + /** 卡片展示用的横幅图片地址。 */ banner: string; + /** 卡片的补充说明。 */ description: string; + /** 列表中的序号或索引值。 */ index: number; + /** 标记卡片所代表的项目是否已完成设置。 */ isSetup: boolean; + /** 卡片标题。 */ name: string; + /** 卡片类别对应的业务编码。 */ type: number; } diff --git a/src/api/model/permissionModel.ts b/src/api/model/permissionModel.ts index d25fb7a..cca1386 100644 --- a/src/api/model/permissionModel.ts +++ b/src/api/model/permissionModel.ts @@ -1,19 +1,30 @@ import type { defineComponent } from 'vue'; import type { RouteMeta } from 'vue-router'; +/** 菜单接口的响应结构。 */ export interface MenuListResult { + /** 可转换为前端动态路由的菜单项。 */ list: Array; } +/** 支持直接使用组件或延迟加载 Vue 组件的路由组件类型。 */ export type Component = ReturnType | (() => Promise) | (() => Promise); +/** 后端菜单项转换前使用的路由数据结构。 */ export interface RouteItem { + /** 路由在 URL 中匹配的路径。 */ path: string; + /** 用于识别路由及关联菜单的唯一名称。 */ name: string; + /** 路由页面组件,也允许由转换逻辑解析的组件路径。 */ component?: Component | string; + /** 命名视图对应的组件集合。 */ components?: Component; + /** 进入当前路由时需要重定向到的目标路径。 */ redirect?: string; + /** Vue Router 使用的菜单、权限及页面元数据。 */ meta: RouteMeta; + /** 当前菜单项下的子路由。 */ children?: Array; } diff --git a/src/api/permission.ts b/src/api/permission.ts index a6f50d8..9992090 100644 --- a/src/api/permission.ts +++ b/src/api/permission.ts @@ -2,9 +2,11 @@ import type { MenuListResult } from '@/api/model/permissionModel'; import { request } from '@/utils/request'; const Api = { + /** 返回供前端构建动态菜单与路由的国际化菜单接口。 */ MenuList: '/get-menu-list-i18n', }; +/** 获取当前应用可用的菜单路由数据。 */ export function getMenuList() { return request.get({ url: Api.MenuList, diff --git a/src/components/LanguageSwitcher.vue b/src/components/LanguageSwitcher.vue index 945f08b..e9c3eec 100644 --- a/src/components/LanguageSwitcher.vue +++ b/src/components/LanguageSwitcher.vue @@ -20,5 +20,6 @@ import { TranslateIcon } from 'tdesign-icons-vue-next'; import { languageList } from '@/locales'; import { useLocale } from '@/locales/useLocale'; +/** 语言菜单选择后持久化设置并更新应用当前语言。 */ const { changeLocale } = useLocale(); diff --git a/src/components/color/index.vue b/src/components/color/index.vue index 24fe7fc..9f5e358 100644 --- a/src/components/color/index.vue +++ b/src/components/color/index.vue @@ -8,14 +8,17 @@ import { DEFAULT_COLOR_OPTIONS } from '@/config/color'; const { value } = defineProps({ value: { + /** 当前色块对应的颜色值。 */ type: String, default: '', }, }); +/** 非预设颜色时显示的彩虹色选择面板背景。 */ const panelColor = 'conic-gradient(from 90deg at 50% 50%, #FF0000 -19.41deg, #FF0000 18.76deg, #FF8A00 59.32deg, #FFE600 99.87deg, #14FF00 141.65deg, #00A3FF 177.72deg, #0500FF 220.23deg, #AD00FF 260.13deg, #FF00C7 300.69deg, #FF0000 340.59deg, #FF0000 378.76deg)'; +/** 根据当前颜色是否属于预设选项生成色块背景样式。 */ const style = computed(() => { return { background: DEFAULT_COLOR_OPTIONS.includes(value) ? value : panelColor, diff --git a/src/components/common-table/index.vue b/src/components/common-table/index.vue index fc09588..4edeee3 100644 --- a/src/components/common-table/index.vue +++ b/src/components/common-table/index.vue @@ -137,15 +137,22 @@ import { t } from '@/locales'; import { useSettingStore } from '@/store'; interface FormData { + /** 搜索条件中的合同名称。 */ name: string; + /** 搜索条件中的合同编号。 */ no: string; + /** 可选的合同状态筛选编码。 */ status?: number; + /** 合同类型筛选值。 */ type: string; } +/** 提供全局布局设置,用于计算表格吸顶区域偏移。 */ const store = useSettingStore(); +/** 用于从表格操作跳转到合同详情页。 */ const router = useRouter(); +/** 合同状态编码到表单显示文案的映射。 */ const CONTRACT_STATUS_OPTIONS = [ { value: CONTRACT_STATUS.FAIL, label: t('components.commonTable.contractStatusEnum.fail') }, { value: CONTRACT_STATUS.AUDIT_PENDING, label: t('components.commonTable.contractStatusEnum.audit') }, @@ -154,11 +161,13 @@ const CONTRACT_STATUS_OPTIONS = [ { value: CONTRACT_STATUS.FINISH, label: t('components.commonTable.contractStatusEnum.finish') }, ]; +/** 合同类型编码到表单显示文案的映射。 */ const CONTRACT_TYPE_OPTIONS = [ { value: CONTRACT_TYPES.MAIN, label: t('components.commonTable.contractTypeEnum.main') }, { value: CONTRACT_TYPES.SUB, label: t('components.commonTable.contractTypeEnum.sub') }, { value: CONTRACT_TYPES.SUPPLEMENT, label: t('components.commonTable.contractTypeEnum.supplement') }, ]; +/** 表格列定义,包括固定列、业务字段和操作列。 */ const COLUMNS: PrimaryTableCol[] = [ { title: t('components.commonTable.contractName'), @@ -202,27 +211,37 @@ const COLUMNS: PrimaryTableCol[] = [ }, ]; +/** 查询表单中需要在重置时恢复的空条件。 */ const searchForm = { name: '', no: '', type: '', }; +/** 当前提交给表格的搜索条件。 */ const formData = ref({ ...searchForm }); +/** 每条列表记录的唯一键字段。 */ const rowKey = 'index'; +/** 表格单元格的垂直对齐方式。 */ const verticalAlign = 'top' as const; +/** 是否为表格行启用悬停效果。 */ const hover = true; +/** 表格分页参数及当前总记录数。 */ const pagination = ref({ defaultPageSize: 20, total: 100, defaultCurrent: 1, }); +/** 控制删除确认弹窗的显示状态。 */ const confirmVisible = ref(false); +/** 当前页面展示的合同列表数据。 */ const data = ref([]); +/** 标记列表请求是否正在进行。 */ const dataLoading = ref(false); +/** 请求列表数据并同步分页总数与加载状态。 */ const fetchData = async () => { dataLoading.value = true; try { @@ -239,7 +258,9 @@ const fetchData = async () => { } }; +/** 当前等待确认删除的记录索引;-1 表示尚未选择记录。 */ const deleteIdx = ref(-1); +/** 根据待删除记录生成确认文案;没有有效索引时返回空文本。 */ const confirmBody = computed(() => { if (deleteIdx.value > -1) { const { name } = data.value[deleteIdx.value]; @@ -248,10 +269,12 @@ const confirmBody = computed(() => { return ''; }); +/** 清除待删除记录索引,结束当前删除操作上下文。 */ const resetIdx = () => { deleteIdx.value = -1; }; +/** 确认删除本地示例记录并更新分页、提示和弹窗状态。 */ const onConfirmDelete = () => { // 真实业务请发起请求 data.value.splice(deleteIdx.value, 1); @@ -261,36 +284,45 @@ const onConfirmDelete = () => { resetIdx(); }; +/** 取消删除操作并清除当前待删除索引。 */ const onCancel = () => { resetIdx(); }; +// 组件首次挂载时加载列表数据。 onMounted(() => { fetchData(); }); +/** 记录被点击删除的行并打开确认弹窗。 */ const handleClickDelete = (slot: { row: { rowIndex: number } }) => { deleteIdx.value = slot.row.rowIndex; confirmVisible.value = true; }; +/** 搜索表单重置事件处理入口,目前仅保留调试信息。 */ const onReset = (val: unknown) => { console.log(val); }; +/** 导航到基础合同详情页面。 */ const handleClickDetail = () => { router.push('/detail/base'); }; +/** 接收查询表单提交事件并记录当前搜索条件。 */ const onSubmit = (val: unknown) => { console.log(val); console.log(formData.value); }; +/** 处理表格分页变化事件;后续可在此接入服务端分页请求。 */ const rehandlePageChange = (pageInfo: PageInfo, newDataSource: TableRowData[]) => { console.log('分页变化', pageInfo, newDataSource); }; +/** 统一接收表格筛选、排序等变化事件。 */ const rehandleChange = (changeParams: unknown, triggerAndData: unknown) => { console.log('统一Change', changeParams, triggerAndData); }; +/** 根据多标签布局计算表头吸顶偏移和滚动容器。 */ const headerAffixedTop = computed( () => ({ diff --git a/src/components/product-card/index.vue b/src/components/product-card/index.vue index e6112b8..2f077e0 100644 --- a/src/components/product-card/index.vue +++ b/src/components/product-card/index.vue @@ -69,28 +69,38 @@ import type { PropType } from 'vue'; import { t } from '@/locales'; export interface CardProductType { + /** 产品卡片类别编码,用于选择对应的展示图标。 */ type: number; + /** 产品是否已经完成配置。 */ isSetup: boolean; + /** 产品说明文案。 */ description: string; + /** 产品展示名称。 */ name: string; + /** 产品在列表中的序号。 */ index: number; } const props = defineProps({ product: { + /** 当前卡片展示的产品数据。 */ type: Object as PropType, required: true, }, }); +/** 向父组件转发管理和删除操作及当前产品数据。 */ const emit = defineEmits(['manage-product', 'delete-item']); +/** 产品类别编码到卡片缩写的展示映射。 */ const typeMap = ['A', 'B', 'C', 'D', 'E']; +/** 请求父组件打开当前产品的管理流程。 */ const handleClickManage = (product: CardProductType) => { emit('manage-product', product); }; +/** 请求父组件删除当前产品。 */ const handleClickDelete = (product: CardProductType) => { emit('delete-item', product); }; diff --git a/src/components/result/index.vue b/src/components/result/index.vue index 1ac0faa..10acc2f 100644 --- a/src/components/result/index.vue +++ b/src/components/result/index.vue @@ -20,23 +20,28 @@ import ResultWifiIcon from '@/assets/assets-result-wifi.svg?component'; const { type } = defineProps({ bgUrl: { + /** 自定义结果背景图片地址;默认使用内置状态图标。 */ type: String, default: '', }, title: { + /** 结果区主标题文本。 */ type: String, default: '', }, tip: { + /** 标题下方的补充说明文本。 */ type: String, default: '', }, type: { + /** 用于选择内置结果图标的状态类型。 */ type: String, default: '', }, }); +/** 将结果类型映射为对应的状态插画组件。 */ const dynamicComponent = computed(() => { switch (type) { case '403': diff --git a/src/components/thumbnail/index.vue b/src/components/thumbnail/index.vue index 8f1437d..03cdb88 100644 --- a/src/components/thumbnail/index.vue +++ b/src/components/thumbnail/index.vue @@ -6,15 +6,18 @@ import { computed } from 'vue'; const { type } = defineProps({ url: { + /** 缩略图资源地址。 */ type: String, default: '', }, type: { + /** 缩略图外观类型,用于选择圆形头像或布局预览样式。 */ type: String, default: 'layout', }, }); +/** 组合基础类名与类型对应的外观类名。 */ const className = computed(() => { return [ 'thumbnail-container', diff --git a/src/components/trend/index.vue b/src/components/trend/index.vue index d7ce2df..832a112 100644 --- a/src/components/trend/index.vue +++ b/src/components/trend/index.vue @@ -25,19 +25,23 @@ import { computed } from 'vue'; const { type, isReverseColor } = defineProps({ type: { + /** 趋势方向,`up` 和 `down` 决定箭头及状态颜色。 */ type: String, default: '', }, describe: { + /** 紧邻趋势图标显示的数值或说明文本。 */ type: [String, Number], default: undefined, }, isReverseColor: { + /** 是否使用反转配色,适用于有色背景上的趋势徽标。 */ type: Boolean, default: false, }, }); +/** 根据趋势方向和反转配色状态生成容器样式类。 */ const containerCls = computed(() => { return [ 'trend-container', @@ -49,6 +53,7 @@ const containerCls = computed(() => { ]; }); +/** 趋势箭头图标的固定样式类。 */ const iconCls = computed(() => ['trend-icon-container']);