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']);