diff --git a/src/api/auth.ts b/src/api/auth.ts index cbbae6f..8b380b8 100644 --- a/src/api/auth.ts +++ b/src/api/auth.ts @@ -8,16 +8,8 @@ import type { } from '@/types/business/user' import { isPhone, isValidPassword } from '@/utils/validate' -/** - * PC 端 clientId(sys_client 种子数据,grantType 含 password)。 - * 与请求头 clientid 同源(见 @/utils/request),改一处即可整体生效。 - */ export const PC_CLIENT_ID = CLIENT_ID -/** - * 账号密码登录:POST /auth/login - * 后端要求请求体含 clientId + grantType + username + password(api-decrypt 未开启,明文即可) - */ export function loginByAccountApi(data: { username: string; password: string }): Promise { return request({ url: '/auth/login', @@ -31,10 +23,6 @@ export function loginByAccountApi(data: { username: string; password: string }): }) } -/** - * 账号密码注册:POST /auth/register - * userType=sys_user;需后端开启注册开关(sys.account.registerUser=true),否则返回「当前系统没有开启注册功能!」 - */ export function registerByAccountApi(data: { username: string; password: string }): Promise { return request({ url: '/auth/register', @@ -53,13 +41,11 @@ export function registerByAccountApi(data: { username: string; password: string const SIX_DIGIT_CODE = /^\d{6}$/ -/** 发送短信验证码 */ export function sendSmsCode(phone: string): Promise { if (!isPhone(phone)) return Promise.reject(new Error('手机号格式不正确')) return Promise.resolve() } -/** 手机验证码登录(mock:验证码须为 6 位数字) */ export function loginBySms(params: LoginBySmsParams): Promise { const { phone, code } = params if (!isPhone(phone)) return Promise.reject(new Error('手机号格式不正确')) @@ -90,7 +76,6 @@ function validateAuthForm( return null } -/** 重置密码 */ export function resetPassword(params: ResetPasswordParams): Promise { const message = validateAuthForm( params.phone, diff --git a/src/api/cases.ts b/src/api/cases.ts index ba9bde9..e47bfe0 100644 --- a/src/api/cases.ts +++ b/src/api/cases.ts @@ -1,10 +1,4 @@ -// 案例库接口(真实后端绑定) -// 后端: vermis-maker com.ruoyi.vermins.controller.pc.web.ProjectCaseUserController -// 前缀: /web/projectCase // -// 使用约定(与项目 SKILL.md 一致): -// 页面/组件禁止直接 import axios,一律经 store 调用本模块的 request。 -// 本文件只放「函数签名 + 请求路径」,不做数据加工、不维护状态。 import { request, serializeQuery } from '@/utils/request' import type { CaseSelectionModel, @@ -13,16 +7,6 @@ import type { ProjectCaseVo, } from '@/types/business/cases' -/** - * 案例库分页列表(返回列表 + 业务数据统计)。 - * - *

规模区间是嵌套对象(`scales[0].lowerLimit`),必须用 serializeQuery 序列化—— - * axios 默认的 `scales[0][lowerLimit]` 后端绑不上,实测 HTTP 500。

- * - * @param bo 筛选条件(businessTypes 按案例表 business_type 原值匹配) - * @param pageNum 页码,从 1 开始(后端 PageQuery) - * @param pageSize 每页条数 - */ export function getCaseList( bo: ProjectCaseUserBo, pageNum: number, @@ -36,11 +20,6 @@ export function getCaseList( }) } -/** - * 案例详情(含项目背景富文本与附件,并回填当前用户是否已收藏)。 - * - *

注意:该接口每次调用都会把案例预览量 +1,勿在轮询 / 重试场景滥用。

- */ export function getCaseDetail(id: string): Promise { return request({ url: `/web/projectCase/${id}`, @@ -48,11 +27,6 @@ export function getCaseDetail(id: string): Promise { }) } -/** - * 案例收藏 / 取消收藏。 - * - *

后端为 toggle 语义:已收藏则取消收藏。需登录态,匿名调用会被后端拦截。

- */ export function collectCase(id: string): Promise { return request({ url: '/web/projectCase/collect', @@ -61,13 +35,6 @@ export function collectCase(id: string): Promise { }) } -/** - * 筛选面板选项(业务类型统计 + 行业 + 规模档位)。 - * - *

左侧筛选除完成时间外的选项都由本接口一次下发:业务类型与案例总数在 - * {@code projectCaseStatisticsVo},行业在 {@code businessIndustry},规模在 - * {@code upperAndLowerLimits}(label 已由后端拼好)。

- */ export function getCaseCategories(): Promise { return request({ url: '/web/projectCase/categories', @@ -75,12 +42,6 @@ export function getCaseCategories(): Promise { }) } -/** - * 案例浏览王(首页「案例库精选」)。 - * - *

不传 type 时返回「各业务类型的浏览王」各一条;传 type 时按案例表 - * business_type 的原值精确匹配,返回该类型全部案例。

- */ export function getFeaturedCases(type?: string): Promise { return request({ url: '/web/projectCase/mostViewed', diff --git a/src/api/contract.ts b/src/api/contract.ts index 8ba4472..ac25892 100644 --- a/src/api/contract.ts +++ b/src/api/contract.ts @@ -3,15 +3,12 @@ import type { Contract, ContractQuery } from '@/types/business/contract' // TODO(api): 待接口文档到位后,将以下 mock 替换为 request 调用 -/** 构造 mock 文件信息 */ function mockFile(name: string, size: number, uploadTime: string): FileInfo { return { name, size, uploadTime, url: '' } } -/** 详情 mock 所属合同 id */ const DETAIL_ID = 'contract-001' -/** 合同列表 mock(3 条,覆盖全部签署状态) */ const MOCK_CONTRACTS: Contract[] = [ { id: 'contract-001', @@ -56,7 +53,6 @@ const MOCK_CONTRACTS: Contract[] = [ }, ] -/** 合同详情 mock */ const CONTRACT_DETAIL: Contract = { id: DETAIL_ID, contractNo: 'C8K2M202408001', @@ -72,7 +68,6 @@ const CONTRACT_DETAIL: Contract = { files: [mockFile('项目需求规格说明书.pdf', 2516582, '2024-10-15')], } -/** 合同列表(keyword 筛选 + 分页) */ export function getContractList(query: ContractQuery): Promise> { const filtered = MOCK_CONTRACTS.filter((item) => { if ( @@ -92,19 +87,16 @@ export function getContractList(query: ContractQuery): Promise { if (id === DETAIL_ID) return Promise.resolve({ ...CONTRACT_DETAIL, files: [...CONTRACT_DETAIL.files] }) const found = MOCK_CONTRACTS.find((item) => item.id === id) ?? null return Promise.resolve(found ? { ...found, files: [...found.files] } : null) } -/** 获取签署二维码(返回有效期) */ export function getSignQr(_id: string): Promise<{ expiresInSeconds: number }> { return Promise.resolve({ expiresInSeconds: 272 }) } -/** 刷新签署二维码(返回有效期) */ export function refreshSignQr(_id: string): Promise<{ expiresInSeconds: number }> { return Promise.resolve({ expiresInSeconds: 272 }) } diff --git a/src/api/demand.ts b/src/api/demand.ts index bb40589..4561635 100644 --- a/src/api/demand.ts +++ b/src/api/demand.ts @@ -1,14 +1,4 @@ -// 需求提报接口(真实后端绑定) -// 草稿 com.ruoyi.vermins.controller.pc.web.WorkUserOrderDraftController → /web/workOrderDraft -// 提交 com.ruoyi.vermins.controller.pc.web.ProjectRequirementUserController → /web/requirementPool/create(WorkOrderDraftBo) -// 同控制器的 /submit(RdProjectBo)是直接提报入口(额外落 vm_rd_project),前端当前未使用 -// 业务类型 com.ruoyi.vermins.controller.pc.ProjectSubmissionWebController → /web/projectSubmission(@SaIgnore 免登录) -// 预算范围 org.dromara.system.controller.system.SysDictDataController → /system/dict/data/type/{dictType} -// 图片换链 org.dromara.resource.controller.SysOssController → /resource/oss/listByIds/{ids} -// 鉴权:业务类型列表免登录;草稿 / 提交 / 字典 / OSS 需登录态(匿名实测 401,故 /demand 路由带 requiresAuth) // -// 使用约定(与项目 SKILL.md 一致): -// 页面/组件禁止直接 import axios,一律经 store 调用本模块;本文件只放「函数签名 + 请求路径」。 import service, { request } from '@/utils/request' import type { ApiResponse } from '@/types/api' import type { @@ -20,21 +10,9 @@ import type { SubmissionBizTypeVo, } from '@/types/business/demand' -/** 业务类型字典类型(sys_dict_type.dict_type)——仅作提报列表为空时的兜底值域 */ export const BIZ_TYPE_DICT = 'vm_biz_type' -/** 预算范围字典类型 */ export const BUDGET_RANGE_DICT = 'vm_budget_range' -/** - * 业务类型列表(项目提报表,**免登录**)。 - * - *

后端 `ProjectSubmissionWebController` 带 `@SaIgnore`,是需求页唯一匿名可用的接口; - * 它与首页 `/web/home-page/service-type-list` 共用同一个 `queryEnabledList()`,只返回 - * `enabled = 1` 且未被逻辑删除的记录。

- * - *

返回项里 `subtitle` 是卡片描述来源、`logoUrl` 是卡片图标来源(实测是 OSS 文件标识, - * 需经 {@link getOssUrls} 换链)。

- */ export function getSubmissionBizTypes(): Promise { return request({ url: '/web/projectSubmission/list', @@ -42,14 +20,6 @@ export function getSubmissionBizTypes(): Promise { }) } -/** - * OSS 文件标识 → 可直接访问的地址。 - * - *

提报列表的 `coverUrl` / `logoUrl` 下发的是 OSS 主键(如 2099753406859292674)而非地址, - * 直接当 `` 用会请求到本站的错误路径上,必须换链。

- * - *

⚠️ 本接口需要登录态;失败时调用方回退前端内置图标,且不阻塞页面。

- */ export function getOssUrls(ids: (string | number)[]): Promise { return request({ url: `/resource/oss/listByIds/${ids.join(',')}`, @@ -57,12 +27,6 @@ export function getOssUrls(ids: (string | number)[]): Promise { }) } -/** - * 业务类型字典(`vm_biz_type`)。 - * - *

⚠️ 仅作**兜底**用:业务类型值域已改为提报列表 {@link getSubmissionBizTypes}; - * 只有当提报表一条可用记录都没有时,store 才回退到本字典,避免页面无可选项。

- */ export function getBizTypeDict(): Promise { return request({ url: `/system/dict/data/type/${BIZ_TYPE_DICT}`, @@ -70,7 +34,6 @@ export function getBizTypeDict(): Promise { }) } -/** 预算范围选项(字典 vm_budget_range) */ export function getBudgetRangeDict(): Promise { return request({ url: `/system/dict/data/type/${BUDGET_RANGE_DICT}`, @@ -78,14 +41,6 @@ export function getBudgetRangeDict(): Promise { }) } -/** - * 读取当前登录用户的需求提报草稿(无草稿返回 null)。 - * - *

⚠️ 后端 `WorkUserOrderDraftController#getDraft` 在"该用户还没有草稿"时会 NPE: - * `VmWorkOrderDraftServiceImpl#queryById` 里 `draft` 为 null 仍继续执行 `draft.getId()`, - * 实测返回 code=500「发生未知异常」。这里刻意绕过统一 `request`(它会对非 200 弹错误提示), - * 直接用原始实例静默兜底:非 200 一律视作"无草稿"。后端补上判空后本段可简化。

- */ export async function getDraftDemand(): Promise { const resp = await service.request>({ url: '/web/workOrderDraft/getDraft', @@ -95,18 +50,6 @@ export async function getDraftDemand(): Promise { return resp.data.data ?? null } -/** - * Demand → 后端 `WorkOrderDraftBo` 请求体。 - * - *

显式列出 BO 的字段,**剔掉纯前端字段 `budgetManual`**(后端 BO/VO 与两张表都没有 - * 「是否手写」的概念,留着虽然会被 Jackson 忽略,但容易被误读成后端支持该标记)。

- * - *

预算范围只有一个字段可下发:预设档位是字典 dictValue,手写时是用户填的金额文本 - * ——后端没有可用的 `budgetCustom`(`WorkOrderDraftBo` 里被注释掉、表也无该列)。

- * - *

`developmentCycle` 是 Integer,表单未填时是空串,必须归一成 null:空串虽然能靠 - * Jackson 的宽松转换塞进去,但依赖默认行为、且语义上是"没填"。

- */ function toBoPayload(demand: Demand): Record { return { id: demand.id, @@ -122,7 +65,6 @@ function toBoPayload(demand: Demand): Record { } } -/** 新增/覆盖草稿(后端 insertByBo 按登录用户 upsert) */ export function saveDraft(demand: Demand): Promise { return request({ url: '/web/workOrderDraft/add', @@ -131,7 +73,6 @@ export function saveDraft(demand: Demand): Promise { }) } -/** 清空当前用户的草稿(后端 cleanHistoryDrafts) */ export function resetDraft(): Promise { return request({ url: '/web/workOrderDraft/reset', @@ -139,7 +80,6 @@ export function resetDraft(): Promise { }) } -/** 上传附件(multipart,后端字段名 file,返回 SysOssVo) */ export function uploadDemandFile(file: File): Promise { const data = new FormData() data.append('file', file) @@ -151,29 +91,6 @@ export function uploadDemandFile(file: File): Promise { }) } -/** - * 提交需求(`POST /web/requirementPool/create`)。 - * - *

入参与草稿共用同一个 BO(`WorkOrderDraftBo`),故请求体直接复用 {@link toBoPayload}, - * 不需要字段名转换。

- * - *

后端 `createRequirement` 一个事务里做三件事:

- *
    - *
  • 落 `vm_project_requirement`(需求主记录,生成项目编号、优先级=未评估、状态=待接洽);
  • - *
  • 把**请求体里的 `attachmentInfo`** 逐条复制成需求附件(只复制 `ossId` 引用到 - * `vm_project_requirement_attachment`,OSS 文件不重复上传)——注意这里是直接吃请求体, - * 不像 `/submit` 那样还得先落一次草稿,所以附件随本次请求一起走;
  • - *
  • 清掉该用户的草稿(`cleanHistoryDrafts`)。
  • - *
- * - *

后端必填校验:`bizType` / `projectName` / `requirementDesc` 任一为空返回 - * 「请完整填写业务类型、项目名称和需求描述」;联系人姓名与电话缺失时先回退登录用户资料, - * 仍为空则报「请完善联系人姓名和联系电话」。

- * - *

⚠️ 本条链路**只落 `vm_project_requirement` 单表**。而「我的项目/需求」列表 - * (`/web/requirementPool/list`)查的是 `vm_rd_project`,因此 create 提交的记录不会出现在 - * 该列表里——要同时落两张表得走后端 `/web/requirementPool/submit`(`RdProjectBo`)。

- */ export function submitDemand(demand: Demand): Promise { return request({ url: '/web/requirementPool/create', diff --git a/src/api/finance.ts b/src/api/finance.ts index 29b1570..dbd15bf 100644 --- a/src/api/finance.ts +++ b/src/api/finance.ts @@ -17,10 +17,6 @@ import { toBills, toPlanBills, type PlanLike } from '@/utils/billVo' import { toPayMethod } from '@/utils/payMeta' import { request } from '@/utils/request' -// 说明:账单 / 支付相关接口已接后端真数据;仅「发票」与「统计」仍是 mock。 -// 另有已下线的遗留演示扫码页(pay.vue)用的一组 mock,见文件中部注释。 - -/** 遗留演示页用的假账单(真账单走 `GET /web/bill/list`,不读这里) */ const MOCK_BILLS: Bill[] = [ { id: 'bill-001', @@ -80,7 +76,6 @@ const MOCK_BILLS: Bill[] = [ }, ] -/** 发票 mock(可变:申请开票后状态在前端内存中翻转演示) */ const MOCK_INVOICES: Invoice[] = [ { id: 'invoice-001', @@ -113,7 +108,6 @@ const MOCK_INVOICES: Invoice[] = [ }, ] -/** 发票抬头 mock(可变,CRUD 在前端内存中演示) */ const MOCK_TITLES: InvoiceTitle[] = [ { id: 'title-001', @@ -131,10 +125,8 @@ const MOCK_TITLES: InvoiceTitle[] = [ }, ] -/** 支付进行单(billId → 当前二维码) */ const MOCK_PAYMENTS = new Map() -/** 已产生支付结果的账单(billId → 结果),预置已支付账单 */ const MOCK_RESULTS = new Map() MOCK_RESULTS.set('bill-001', { method: 'wechat', @@ -163,18 +155,15 @@ const DEFAULT_STATS: FinanceStats = { ], } -/** 财务统计(period 为展示周期参数,mock 恒返回原型数据) */ export function getFinanceStats(period?: string): Promise { void period return Promise.resolve(structuredClone(DEFAULT_STATS)) } -/** 真账单 id 一定是纯数字(`vm_bill.id` 是 bigint);非数字只可能来自已下线的演示mock */ function isRealBillId(id: string): boolean { return /^\d+$/.test(id) } -/** 拉取「当前登录用户」的全部账单(`GET /web/bill/list`,不带 ids) */ async function fetchOwnBills(): Promise { const rows = await request({ url: '/web/bill/list', method: 'get' }) return toBills(rows) @@ -190,13 +179,6 @@ function matchBillKeyword(item: Bill, keyword: string): boolean { ) } -/** - * 账单列表(筛选 + 分页)。 - * - *

⚠️ `GET /web/bill/list` 只按登录用户返回**全量**账单,后端没有 pageNum / keyword / - * status 查询参数;单个客户的账单量级是「几条 ~ 几十条」,故筛选与分页放在前端做。 - * 若日后账单量变大,应给该端点补后端分页参数,这里再切成一次请求。

- */ export async function getBillList(query: BillQuery): Promise> { const all = await fetchOwnBills() const filtered = all.filter((item) => { @@ -207,22 +189,15 @@ export async function getBillList(query: BillQuery): Promise> { return { list: filtered.slice(start, start + query.pageSize), total: filtered.length } } -/** 账单详情(不存在返回 null) */ export async function getBillDetail(id: string): Promise { const rows = await request({ url: '/web/bill/list', method: 'get', params: { ids: id } }) return toBills(rows)[0] ?? null } // ═══════════════════════════════════════════════════════════════════════ -// 遗留演示扫码页(`/finance/bills/:id/pay`,页面 pay.vue) // --------------------------------------------------------------------- -// 该页已无任何入口(收银台 checkout.vue 取代了它),但按既定决定保留。 -// 它用的是下面这几个 mock 函数,与真账单互不干扰:真账单 id 一定是数字, -// 假账单 id 形如 `bill-001`,两条路径靠 `isRealBillId` 分流。 -// 若要下线该页,这一整段(含 MOCK_PAYMENTS / MOCK_RESULTS)可一并删除。 // ═══════════════════════════════════════════════════════════════════════ -/** 创建支付单(遗留页演示用:生成二维码支付信息) */ export function createPayment(billId: string, method: PayMethod): Promise { const bill = MOCK_BILLS.find((item) => item.id === billId) if (!bill) return Promise.reject(new Error('账单不存在')) @@ -236,21 +211,10 @@ export function createPayment(billId: string, method: PayMethod): Promise { return createPayment(billId, method) } -/** - * 查询支付结果。 - * - *

真账单:直接读 `vm_bill` —— 账单被回调置为 PAID 时,`pay_time` / - * `transaction_no` / `pay_channel` 已由后端一并回写,这里拼出结果页所需结构; - * 未支付则返回 null。

- * - *

假账单(id 形如 `bill-001`):走下面的遗留演示逻辑。真账单 id 一定是数字, - * 故只有已下线的 pay.vue 会命中这条分支。

- */ export async function getPayResult(billId: string): Promise { if (isRealBillId(billId)) { const bill = await getBillDetail(billId) @@ -266,7 +230,6 @@ export async function getPayResult(billId: string): Promise { const existing = MOCK_RESULTS.get(billId) if (existing) return Promise.resolve(structuredClone(existing)) @@ -275,7 +238,6 @@ function getLegacyPayResult(billId: string): Promise { const bill = MOCK_BILLS.find((item) => item.id === billId) if (!payment || !bill) return Promise.resolve(null) - // 演示:存在支付单即视为完成支付(createPayment 由「完成支付」触发) const tradeNo = bill.tradeNo ?? 'T20260819153035678K2M001' if (bill.status !== '已支付') { bill.status = '已支付' @@ -302,7 +264,6 @@ function matchInvoiceKeyword(item: Invoice, keyword: string): boolean { ) } -/** 发票列表(筛选 + 分页) */ export function getInvoiceList(query: InvoiceQuery): Promise> { const filtered = MOCK_INVOICES.filter((item) => { if (query.status !== 'all' && item.status !== query.status) return false @@ -315,7 +276,6 @@ export function getInvoiceList(query: InvoiceQuery): Promise }) } -/** 申请开票(演示:状态置为开票中),返回最新发票 */ export function applyInvoice(id: string): Promise { const found = MOCK_INVOICES.find((item) => item.id === id) if (!found) return Promise.reject(new Error('发票记录不存在')) @@ -323,12 +283,10 @@ export function applyInvoice(id: string): Promise { return Promise.resolve({ ...found }) } -/** 发票抬头列表 */ export function getInvoiceTitles(): Promise { return Promise.resolve(MOCK_TITLES.map((item) => ({ ...item }))) } -/** 新增发票抬头 */ export function createInvoiceTitle(payload: InvoiceTitlePayload): Promise { const created: InvoiceTitle = { id: `title-${Date.now()}`, @@ -339,7 +297,6 @@ export function createInvoiceTitle(payload: InvoiceTitlePayload): Promise { const found = MOCK_TITLES.find((item) => item.id === id) if (!found) return Promise.reject(new Error('抬头不存在')) @@ -349,7 +306,6 @@ export function updateInvoiceTitle(id: string, payload: InvoiceTitlePayload): Pr return Promise.resolve({ ...found }) } -/** 删除发票抬头 */ export function deleteInvoiceTitle(id: string): Promise { const index = MOCK_TITLES.findIndex((item) => item.id === id) if (index < 0) return Promise.reject(new Error('抬头不存在')) @@ -357,7 +313,6 @@ export function deleteInvoiceTitle(id: string): Promise { return Promise.resolve() } -/** 设为默认抬头(唯一默认) */ export function setDefaultTitle(id: string): Promise { for (const item of MOCK_TITLES) { item.isDefault = item.id === id @@ -365,30 +320,13 @@ export function setDefaultTitle(id: string): Promise { return Promise.resolve(MOCK_TITLES.map((item) => ({ ...item }))) } -/** 导出报表(演示:稍后由页面提示成功) */ export function exportReport(): Promise { return Promise.resolve() } // ═══════════════════════════════════════════════════════════════════════ -// 收银台(确认支付)——以下为**真实后端接口**,不是 mock -// 后端类:vermis-modules/…/controller/pc/pay/WebScanPayController,类级 @SaIgnore(匿名可调) // ═══════════════════════════════════════════════════════════════════════ -/** - * 取收银台「订单明细」——**复用项目详情「合同财务」那个现成接口**,不另开端点。 - * - *

`GET /web/requirementPool/get/finance/{requirementId}`(`ProjectRequirementUserController`) - * 的 `{id}` 是**需求 id**;后端把「需求 + 项目」拼成一条联合结构(`loadProject` 用 - * `vm_rd_project.requirement_id` 反查项目),再把该项目的付款计划随 `billPlans` 一并下发。

- * - *

本栈支付口径是 `vm_bill_plan.id`(`vm_finance_payment.bill_id` 实测存的就是计划 id), - * 故订单明细直接取这份 `billPlans`,只保留**本次要付的期**: - * URL 带 `ids`(期次 id)时按期次过滤,不带则取状态为「待支付」的期。

- * - * @param requirementId 需求 id(项目详情路由 `:id`) - * @param ids 期次 id(`vm_bill_plan.id`)列表,可选,用于精确指定付哪一期 - */ export async function getCheckoutBills(requirementId: string, ids: string[] = []): Promise { if (!/^\d+$/.test(requirementId)) return [] const vo = await request<{ billPlans?: PlanLike[] }>({ @@ -401,12 +339,6 @@ export async function getCheckoutBills(requirementId: string, ids: string[] = [] : all.filter((bill) => bill.status === '待支付') } -/** - * 支付结果(收银台「我已完成支付」→ 结果页)。 - * - *

口径同 {@link getCheckoutBills}:按**需求 id + 期次 id** 从 `billPlans` 里取出该期, - * 支付单状态为 `SUCCESS` 才算已支付——计划本身的 status 可能还没被回调推到 DONE。

- */ export async function getPlanPayResult(requirementId: string, planId: string): Promise { const bills = await getCheckoutBills(requirementId, [planId]) const bill = bills[0] @@ -420,17 +352,6 @@ export async function getPlanPayResult(requirementId: string, planId: string): P } } -/** - * 微信 Native 下单(PC 网站扫码):`POST /pay/web/wechat/native`,`@SaIgnore`。 - * - * @param orderNo 商户订单号(前端生成,见 `utils/payMeta.ts#createMerchantOrderNo`) - * @param amount 支付金额,单位 **元**(后端内部 `×100` 转「分」提交微信) - * @param billIds 本笔支付覆盖的账单 id(合并支付传多张)。 - * 后端落 `vm_finance_payment`(status=CREATED)时把它序列化进 - * `request_payload`,支付成功回调据此为**每张账单**落一行 - * `vm_finance_payment_bill`,缺了它回调分摊落库会跳过。 - * @returns `codeUrl`(形如 `weixin://wxpay/bizpayurl?pr=xxx`),前端渲染成二维码供扫 - */ export function createWechatNativeOrder( orderNo: string, amount: number, @@ -443,16 +364,6 @@ export function createWechatNativeOrder( }) } -/** - * 支付宝电脑网站支付下单:`POST /pay/web/alipay/page`,`@SaIgnore`。 - * - *

入参对应后端 `IFinancePaymentBo`。其 `outTradeNo` / `status` 上的 `@NotBlank` - * 只声明在 AddGroup / EditGroup 分组上,而控制器用的是默认分组 ⇒ 只传 - * `outTradeNo` + `amount` 即可(`payChannel` / `status` 由后端自己补),不会校验失败。

- * - * @returns `formBody` —— 后端走 `pageExecute(request, "GET")`,实测内容是 - * **支付宝收银台跳转地址**(`https://…/gateway.do?…`)而不是 HTML 表单;前端两种形态都兜住。 - */ export function createAlipayPageOrder( outTradeNo: string, amount: number, diff --git a/src/api/home.ts b/src/api/home.ts index 5bd904e..236c091 100644 --- a/src/api/home.ts +++ b/src/api/home.ts @@ -1,11 +1,4 @@ -// 首页接口(真实后端绑定) -// 后端: vermis-maker com.ruoyi.vermins.controller.pc.web.UserSideWebHomePageController -// 前缀: /web/home-page 鉴权: 公开接口,无需 token -// 门户入口: com.ruoyi.vermins.controller.pc.web.IPortalEntryUserController(首页快捷入口功能,并入本文件) // -// 使用约定(与项目 SKILL.md 一致): -// 页面/组件禁止直接 import axios,一律经 store 调用本模块的 request。 -// 本文件只放「函数签名 + 请求路径」,不写业务逻辑。 import { request } from '@/utils/request' import type { AgreementFormVo, @@ -17,7 +10,6 @@ import type { ProjectSubmissionVo, } from '@/types/business/home' -/** 项目状态统计 */ export function getProjectStatusCount(): Promise { return request({ url: '/web/home-page/project-status-count', @@ -25,7 +17,6 @@ export function getProjectStatusCount(): Promise { }) } -/** 业务服务类型列表 */ export function getServiceTypeList(): Promise { return request({ url: '/web/home-page/service-type-list', @@ -33,7 +24,6 @@ export function getServiceTypeList(): Promise { }) } -/** 业务类型详情(聚合 VO:projectSubmission / projectServiceType / projectSubmissionAttachment / projectSubmissionCatalog) */ export function getServiceTypeDetail(id: number | string): Promise { return request({ url: `/web/home-page/service-type-detail/${id}`, @@ -41,7 +31,6 @@ export function getServiceTypeDetail(id: number | string): Promise { return request({ url: '/web/home-page/carousel-list', @@ -49,7 +38,6 @@ export function getCarouselList(): Promise { }) } -/** 平台介绍(富文本 HTML) */ export function getPlatformIntro(): Promise { return request({ url: '/web/home-page/platform-intro', @@ -57,7 +45,6 @@ export function getPlatformIntro(): Promise { }) } -/** 联系信息(富文本 HTML) */ export function getContactInfo(): Promise { return request({ url: '/web/home-page/contact-info', @@ -65,14 +52,6 @@ export function getContactInfo(): Promise { }) } -// 首页「案例库精选」接口(/web/projectCase/mostViewed)按资源归位到 `@/api/cases` 的 getFeaturedCases。 - -/** - * 查询用户门户入口列表 - * - *

登录态返回该用户个性化后的分组结果;匿名返回固定目录。 - * 两组数据由 groupType 区分(1 = 快捷、0 = 其他)。

- */ export function getPortalEntryList(): Promise { return request({ url: '/vermins/portalEntryUser/list', @@ -80,14 +59,6 @@ export function getPortalEntryList(): Promise { }) } -/** - * 快捷 / 其他入口互转 - * - *

后端 add 的入参是 @RequestParam,必须走 query 而非 body。

- * - * @param id 入口 id - * @param type 目标分组:1 = 快捷、0 = 其他 - */ export function switchPortalEntryGroup(id: number, type: PortalEntryGroup): Promise { return request({ url: '/vermins/portalEntryUser/add', diff --git a/src/api/message.ts b/src/api/message.ts index 29ef993..324a809 100644 --- a/src/api/message.ts +++ b/src/api/message.ts @@ -3,7 +3,6 @@ import type { Message, MessageQuery } from '@/types/business/message' // TODO(api): 待接口文档到位后,将以下 mock 替换为 request 调用 -/** 消息 mock(可变,已读状态在前端内存中翻转演示) */ const MOCK_MESSAGES: Message[] = [ { id: 'msg-001', @@ -107,7 +106,6 @@ function applyFilters(query: MessageQuery): Message[] { }) } -/** 消息列表(筛选 + 分页) */ export function getMessageList(query: MessageQuery): Promise> { const filtered = applyFilters(query) const start = (query.page - 1) * query.pageSize @@ -117,13 +115,11 @@ export function getMessageList(query: MessageQuery): Promise }) } -/** 消息详情(不存在返回 null) */ export function getMessageDetail(id: string): Promise { const found = MOCK_MESSAGES.find((item) => item.id === id) ?? null return Promise.resolve(found ? { ...found } : null) } -/** 全部标记已读 */ export function markAllRead(): Promise { for (const item of MOCK_MESSAGES) { item.isRead = true @@ -131,14 +127,12 @@ export function markAllRead(): Promise { return Promise.resolve() } -/** 单条标记已读 */ export function markRead(id: string): Promise { const found = MOCK_MESSAGES.find((item) => item.id === id) if (found) found.isRead = true return Promise.resolve() } -/** 各分类消息总数(tab 角标) */ export function getTabCounts(): Promise<{ all: number; 在线客服: number; 状态通知: number; 系统通知: number }> { const counts = { all: MOCK_MESSAGES.length, 在线客服: 0, 状态通知: 0, 系统通知: 0 } for (const item of MOCK_MESSAGES) { @@ -147,7 +141,6 @@ export function getTabCounts(): Promise<{ all: number; 在线客服: number; 状 return Promise.resolve(counts) } -/** 未读消息总数(头部角标) */ export function getUnreadCount(): Promise { return Promise.resolve(MOCK_MESSAGES.filter((item) => !item.isRead).length) } diff --git a/src/api/oss.ts b/src/api/oss.ts index 1d49d5f..7edcc63 100644 --- a/src/api/oss.ts +++ b/src/api/oss.ts @@ -1,15 +1,5 @@ import service from '@/utils/request' -/** - * 同源预览:后端从 OSS 读取字节后以 `inline` 方式返回,绕开阿里云 OSS 桶「强制下载」配置。 - * - *

⚠️ 该端点返回的是裸字节(非 `R.ok()` 包装的 `ApiResponse`),故不走统一的 - * `request` 解包逻辑,直接用底层 axios 实例拿 `blob`:请求拦截器已自动带上 - * `Authorization` 与 `clientid` 头,后端据此放行(端点需登录)。

- * - *

用 blob 而非 `window.open(url)` 的关键:blob URL 自身不带 `Content-Disposition`, - * 天然绕开 OSS 的强制下载;且全程同源,不受 OSS 跨域 / 强制下载限制。

- */ export async function fetchOssPreviewBlob(ossId: string | number): Promise { const resp = await service.get(`/web/workOrderDraft/preview/${ossId}`, { responseType: 'blob', diff --git a/src/api/profile.ts b/src/api/profile.ts index 0b3e7b8..21e1446 100644 --- a/src/api/profile.ts +++ b/src/api/profile.ts @@ -14,7 +14,6 @@ import type { // TODO(api): 待接口文档到位后,将以下 mock 替换为 request 调用(页面 → store → api 数据流不变) -/** 账号资料 mock(可变,昵称/绑定等操作在前端内存中演示) */ const MOCK_PROFILE: Profile = { nickname: '王永志', phone: '186****618', @@ -22,57 +21,48 @@ const MOCK_PROFILE: Profile = { passwordModifiedAt: '15天前', } -/** 获取账号资料 */ export function getProfile(): Promise { return Promise.resolve({ ...MOCK_PROFILE }) } -/** 修改昵称 */ export function updateNickname(name: string): Promise { MOCK_PROFILE.nickname = name return Promise.resolve({ ...MOCK_PROFILE }) } -/** 修改密码(验证码 + 新密码) */ export function changePassword(params: ChangePasswordParams): Promise { MOCK_PROFILE.passwordModifiedAt = '刚刚' void params return Promise.resolve() } -/** 绑定/换绑手机号 */ export function bindPhone(phone: string, code: string): Promise { void code MOCK_PROFILE.phone = phone return Promise.resolve({ ...MOCK_PROFILE }) } -/** 绑定/换绑邮箱 */ export function bindEmail(email: string, code: string): Promise { void code MOCK_PROFILE.email = email return Promise.resolve({ ...MOCK_PROFILE }) } -/** 取消绑定邮箱 */ export function unbindEmail(): Promise { MOCK_PROFILE.email = '' return Promise.resolve({ ...MOCK_PROFILE }) } -/** 注销前安全身份验证 */ export function verifyIdentity(phone: string, code: string): Promise { void phone void code return Promise.resolve() } -/** 注销账号 */ export function deleteAccount(): Promise { return Promise.resolve() } -/** 收货地址 mock(isDefault 混合) */ const MOCK_ADDRESSES: Address[] = [ { id: 'addr-1', @@ -116,12 +106,10 @@ function paginate(list: T[], query: ListQuery): PageResult { } } -/** 收货地址列表(分页) */ export function getAddresses(query: ListQuery): Promise> { return Promise.resolve(paginate(MOCK_ADDRESSES, query)) } -/** 新增收货地址 */ export function createAddress(input: Omit): Promise
{ const created: Address = { ...input, @@ -132,7 +120,6 @@ export function createAddress(input: Omit): Promise return Promise.resolve({ ...created }) } -/** 编辑收货地址 */ export function updateAddress(id: string, input: Omit): Promise
{ const found = MOCK_ADDRESSES.find((item) => item.id === id) if (!found) return Promise.reject(new Error('地址不存在')) @@ -140,14 +127,12 @@ export function updateAddress(id: string, input: Omit { const index = MOCK_ADDRESSES.findIndex((item) => item.id === id) if (index >= 0) MOCK_ADDRESSES.splice(index, 1) return Promise.resolve() } -/** 设为默认地址 */ export function setDefaultAddress(id: string): Promise { for (const item of MOCK_ADDRESSES) { item.isDefault = item.id === id @@ -155,7 +140,6 @@ export function setDefaultAddress(id: string): Promise { return Promise.resolve(MOCK_ADDRESSES.map((item) => ({ ...item }))) } -/** 我的收藏 mock(4 条已收藏案例,字段与案例库原型一致) */ const MOCK_FAVORITES: Case[] = [ { id: 'fav-1', @@ -243,7 +227,6 @@ const MOCK_FAVORITES: Case[] = [ }, ] -/** 我的收藏(关键字/分类筛选 + 分页) */ export function getFavorites(query: FavoritesQuery): Promise> { const filtered = MOCK_FAVORITES.filter((item) => { if (query.category !== 'all' && item.category !== query.category) return false @@ -257,7 +240,6 @@ export function getFavorites(query: FavoritesQuery): Promise> { }) } -/** 收藏分类计数(分类快捷按钮角标) */ export function getCaseCounts(): Promise>> { const counts: Partial> = { internet: 1, @@ -268,7 +250,6 @@ export function getCaseCounts(): Promise>> return Promise.resolve(counts) } -/** 资质 mock(状态混合:已认证/审核中/未通过) */ const MOCK_QUALIFICATIONS: Qualification[] = [ { id: 'qual-1', @@ -324,12 +305,10 @@ const MOCK_QUALIFICATIONS: Qualification[] = [ }, ] -/** 资质列表(分页) */ export function getQualifications(query: ListQuery): Promise> { return Promise.resolve(paginate(MOCK_QUALIFICATIONS, query)) } -/** 新增资质(提交后进入审核中) */ export function createQualification(input: QualificationInput): Promise { const created: Qualification = { ...input, @@ -340,7 +319,6 @@ export function createQualification(input: QualificationInput): Promise { const found = MOCK_QUALIFICATIONS.find((item) => item.id === id) if (!found) return Promise.reject(new Error('资质不存在')) @@ -355,20 +333,17 @@ export function updateQualification(id: string, input: QualificationInput): Prom return Promise.resolve({ ...found }) } -/** 删除资质 */ export function deleteQualification(id: string): Promise { const index = MOCK_QUALIFICATIONS.findIndex((item) => item.id === id) if (index >= 0) MOCK_QUALIFICATIONS.splice(index, 1) return Promise.resolve() } -/** 提交意见反馈 */ export function submitFeedback(feedback: Feedback): Promise { void feedback return Promise.resolve() } -/** 帮助中心 FAQ */ export function getHelpFaqs(): Promise { return Promise.resolve([ { diff --git a/src/api/project.ts b/src/api/project.ts index 0fc7f2a..1f760fd 100644 --- a/src/api/project.ts +++ b/src/api/project.ts @@ -12,55 +12,29 @@ import { request, serializeQuery } from '@/utils/request' import { formatDate } from '@/utils/format' // ───────────────────────────────────────────────────────────────────────────── -// 列表:真实接口 // GET /web/requirementPool/list → ProjectRequirementUserController#list // → ProjectRequirementServiceImpl#queryUserPageList -// 入参 RdProjectBo + PageQuery;出参 ProjectRequirementAndCountVo // { requirementPage: { total, rows: RdProjectVo[] }, requirementStatistics: null } -// 鉴权:需登录态(匿名 401);每请求带 clientid 头(见 utils/request.ts 拦截器)。 -// 筛选参数实测(tools/probe_project_api.py): // key → like projectName OR projectNo OR requirementDesc -// businessTypes → IN business_type(**多选**;值是提报表主键 id,不是类型名) -// status → eq status(码值,见 RdProjectStatus) -// beginTime/endTime → between create_time(不是 submit_time!) // pageNum/pageSize → PageQuery -// ⚠️ 主表已改为**需求表** vm_project_requirement(LEFT JOIN 项目表),未立项的需求也会出现; -// 未立项行 progress 为 null(显示「—」)、status 回落需求表中的 INITIATING。 -// ⚠️ 列表行的 businessType 是 SQL 里 JOIN 提报表**翻译后的中文名称**(如「互联网软件」), -// 与筛选参数 businessType(提报表 id)**不是同一口径**,渲染时不能用 typeCounts 反查。 // ───────────────────────────────────────────────────────────────────────────── // ───────────────────────────────────────────────────────────────────────────── -// 业务类型筛选条件:真实接口 // GET /web/requirementPool/getFilterConditions // → ProjectRequirementUserController#getFilterConditions // → ProjectRequirementServiceImpl#getFilterConditions -// 出参 ProjectRequirementStatisticsVo: -// { total: 该用户需求总数, // businessTypeCounts: [{ businessTypeId, businessTypeLabel, count }] } -// 口径:**全量、不分页**,所以件数不会随 pageNum/pageSize 变化,适合当筛选栏的固定值域; -// businessTypeId = vm_project_submission 主键 id(直接回传当 businessType 筛选参数); -// businessTypeLabel = 该表的 business_type 名称;提报表里没命中的脏数据不计入。 -// ⚠️ /list 响应里的 requirementStatistics 后端仍是注释状态(实测恒 null),统计一律走本端点。 // ───────────────────────────────────────────────────────────────────────────── -/** 两位补零 */ function pad(value: number): string { return String(value).padStart(2, '0') } -/** Date → 'yyyy-MM-dd HH:mm:ss'(后端 RdProjectBo.beginTime/endTime 是 Date,实测该格式可绑定) */ function toDateTime(date: Date, endOfDay: boolean): string { const ymd = `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}` return `${ymd} ${endOfDay ? '23:59:59' : '00:00:00'}` } -/** - * 提交时间条件 → 后端 `beginTime` / `endTime`(都落在 `create_time` 上)。 - * - *

自选区间优先(UI 上两组互斥,这里再兜一层);结束日一律补到 23:59:59, - * 否则 `endTime=2026-09-30` 会被绑成当天 00:00:00 而漏掉当天数据。

- */ function toTimeRange(query: ProjectQuery): { beginTime?: string; endTime?: string } { if (query.startDate || query.endDate) { return { @@ -77,21 +51,15 @@ function toTimeRange(query: ProjectQuery): { beginTime?: string; endTime?: strin return { beginTime: toDateTime(start, false), endTime: toDateTime(new Date(), true) } } -/** 项目列表(真实接口:服务端筛选 + 分页;业务类型统计走 getProjectFilterConditions) */ export function getProjectList(query: ProjectQuery): Promise { return request({ url: '/web/requirementPool/list', method: 'get', - // 多选数组必须走 serializeQuery,展开成 businessTypes[0]=…&businessTypes[1]=… - //(与 api/cases.ts 同一做法;不传则走 axios 默认的 businessTypes[]=,实测后端也能绑, - // 但这里取与文档/案例库一致的索引形式,避免依赖框架默认行为) paramsSerializer: { serialize: serializeQuery }, params: { pageNum: query.pageNum, pageSize: query.pageSize, - // 空串不出现在 querystring 里,与后端 eqIfText 的「有值才等值匹配」语义一致 key: query.keyword || undefined, - // 多选:空数组不发;非空由 serializeQuery 展开成 businessTypes[0]=…&businessTypes[1]=… businessTypes: query.businessTypes.length > 0 ? [...query.businessTypes] : undefined, status: query.status || undefined, ...toTimeRange(query), @@ -99,12 +67,6 @@ export function getProjectList(query: ProjectQuery): Promise }) } -/** - * 业务类型筛选条件(左侧筛选栏「业务类型」的值域 + 件数)。 - * - *

与列表分开取:`/list` 的 `requirementStatistics` 后端恒为 null,统计由本端点单独下发, - * 且是**全量口径**(不随筛选、分页变化),所以进页面拉一次即可。

- */ export function getProjectFilterConditions(): Promise { return request({ url: '/web/requirementPool/getFilterConditions', @@ -112,17 +74,6 @@ export function getProjectFilterConditions(): Promise { }) } -/** - * 已完成项目(申请售后页「项目名称」下拉的候选)。 - * - *

直接复用列表接口做状态过滤:`status=COMPLETED` 在后端比的是 - * `COALESCE(vm_rd_project.status, vm_project_requirement.status)`,而 `COMPLETED` 只会 - * 出现在**项目表**(未立项的需求是 `INITIATING`)⇒ 结果天然就是「自己名下已立项且已完成的项目」, - * 与后端申请售后的准入校验(只有 COMPLETED 可申请)口径一致。

- * - *

售后申请场景下候选量级不大,一次取回较大分页(后端无专用端点);后端默认排序 - * `update_time DESC`。返回行的 `id` = **需求 id**,正是申请接口要传的那个 id。

- */ export function getCompletedProjects(): Promise { return request({ url: '/web/requirementPool/list', @@ -136,7 +87,6 @@ export function getCompletedProjects(): Promise { } // ───────────────────────────────────────────────────────────────────────────── -// 详情:真实接口(**4 个页签各一个端点**,同帧并行取回后合并) // GET /web/requirementPool/get/progress/{id} → ProjectRequirementProgressVo // GET /web/requirementPool/get/files/{id} → ProjectRequirementFilesVo // GET /web/requirementPool/get/finance/{id} → ProjectRequirementFinanceVo @@ -144,26 +94,10 @@ export function getCompletedProjects(): Promise { // → ProjectRequirementUserController#getProgress / #getFiles / #getFinance / #getAfterSales // → ProjectRequirementServiceImpl#queryProgress / queryFiles / queryFinance / queryAfterSales // -// 4 个 VO 都继承 ProjectRequirementBaseVo(基础信息始终带)⇒ 任一响应里都有项目名 / -// 编号 / 业务类型 / 状态 / 提交时间,所以详情页顶部信息卡只依赖其中一支即可,切页签不缺数据。 -// 首屏用 getProjectDetailBundle **同帧并行**发 4 个请求(一次到位,避免首屏缺数据); -// **之后每次点击页签**再用 getProjectDetailTab 只拉对应那一支(点一次 = 一次请求), -// 响应回填到 store 里的 bundle 后重新映射 ⇒ 页面始终是**最新数据**,不重拉另外三支。 -// 出参由 stores/modules/project.ts 缓存成 bundle,经 utils/projectVo.ts#toProjectDetail -// 映射成详情页沿用的 Project 形态。 -// ⚠️ id 传的是**需求 id**(vm_project_requirement.id)= 列表行 RdProjectVo.id; -// 未立项的需求也能查到(项目侧字段为空);不存在 / 非本人 → 后端 4 支 data 均为 null。 // ───────────────────────────────────────────────────────────────────────────── -/** - * 详情页签(= `RequirementDetailBundle` 的键名,也就是 4 个端点的后缀)。 - * - *

`views/project/detail.vue` 里的 `DetailTab` 是同一组值;那边不 import 本模块 - * (页面层不直接依赖 api),靠字面量对齐。

- */ export type ProjectDetailTab = 'progress' | 'files' | 'finance' | 'afterSales' -/** 页签 → 端点(4 支都继承 ProjectRequirementBaseVo,基础信息任一支都有) */ const DETAIL_TAB_URL: Record = { progress: '/web/requirementPool/get/progress', files: '/web/requirementPool/get/files', @@ -171,14 +105,6 @@ const DETAIL_TAB_URL: Record = { afterSales: '/web/requirementPool/get/afterSales', } -/** - * 单个页签取数(**点一次页签 = 一次请求**,拿该页签的最新数据)。 - * - *

返回类型按页签收窄:`getProjectDetailTab(id, 'finance')` → `RequirementFinanceVo | null`, - * 所以调用方可以直接把结果写回 bundle 的对应键。

- * - *

`null` = 需求不存在 / 不属于当前用户(后端 `data: null`),调用方应保留现有数据并提示。

- */ export function getProjectDetailTab( id: string, tab: T, @@ -189,12 +115,6 @@ export function getProjectDetailTab( }) } -/** - * 详情四支并行取回(**首屏用**);任一为 null ⇒ 整个 bundle 为 null。 - * - *

4 支同源(都查同一行需求),正常不会只缺一支;缺一支即视为「需求不存在 / 非本人」, - * 详情页走整页空态。

- */ export function getProjectDetailBundle(id: string): Promise { return Promise.all([ getProjectDetailTab(id, 'progress'), @@ -208,31 +128,12 @@ export function getProjectDetailBundle(id: string): Promise只传 OSS、不落业务表;返回项带 `ossId`,提交时由后端转存成售后附件。 - * 后端响应没有文件大小,大小取本地 `File.size`。

- */ export function uploadAfterSalesFile(file: File): Promise { const data = new FormData() data.append('file', file) @@ -250,12 +151,6 @@ export function uploadAfterSalesFile(file: File): Promise })) } -/** - * 申请售后(用户端)。 - * - *

`id` 是**需求 id**(= 详情页路由参数);`payload` 的 `reason` / `note` 分别对应 - * 页面的「问题描述」与「补充备注」。

- */ export function submitAfterSales( id: string, payload: AfterSalesPayload, @@ -268,17 +163,11 @@ export function submitAfterSales( type: payload.type, reason: payload.reason, note: payload.note, - // 空数组是安全的(后端 `appendAttachments` 对空集合直接 return,不 NPE) attachmentOssIds: payload.attachmentOssIds, }, }) } -/** - * 撤回售后申请(用户端)。 - * - *

`id` 传**需求 id**;`reason` 是撤回原因(选填,后端会存进 `withdraw_reason`)。

- */ export function cancelAfterSales(id: string, reason = ''): Promise { return request({ url: '/web/requirementPool/afterSales/withdraw', diff --git a/src/api/service.ts b/src/api/service.ts index 092286b..37a430e 100644 --- a/src/api/service.ts +++ b/src/api/service.ts @@ -15,7 +15,6 @@ function nowTime(): string { return `今天 ${pad(date.getHours())}:${pad(date.getMinutes())}` } -/** 历史会话(欢迎语 + 用户提问 + 文件资料) */ export function getChatHistory(): Promise { return Promise.resolve([ { @@ -40,7 +39,6 @@ export function getChatHistory(): Promise { ]) } -/** 发送文本消息(echo 用户消息,携带当前时间) */ export function sendChatMessage(content: string): Promise { return Promise.resolve({ id: nextId('chat'), @@ -50,7 +48,6 @@ export function sendChatMessage(content: string): Promise { }) } -/** 上传聊天文件(生成文件卡片消息) */ export function uploadChatFile(file: File): Promise { return Promise.resolve({ id: nextId('chat'), @@ -61,7 +58,6 @@ export function uploadChatFile(file: File): Promise { }) } -/** 客服自动回复 */ export function mockAutoReply(): Promise { return Promise.resolve({ id: nextId('chat'), diff --git a/src/api/user.ts b/src/api/user.ts index 620c70c..1ca857e 100644 --- a/src/api/user.ts +++ b/src/api/user.ts @@ -1,15 +1,6 @@ -// 用户资料接口(真实后端绑定) -// 后端:org.dromara.system.controller.system.SysUserController#profile → /system/user/profile -// 鉴权:需登录态 import { request } from '@/utils/request' import type { UserProfileVo } from '@/types/business/user' -/** - * 当前登录用户资料(需求提报页预填联系人姓名 / 电话)。 - * - *

⚠️ 后端返回的是 `R`,用户对象嵌在 **`data.user`** 里(同级还有 roles / posts), - * 不是平铺在 data 上——这里在 api 层解包,调用方拿到的是用户对象本身。

- */ export async function getUserProfile(): Promise { const data = await request<{ user: UserProfileVo }>({ url: '/system/user/profile', diff --git a/src/components/AppFooter.vue b/src/components/AppFooter.vue index 5ba505a..296d47e 100644 --- a/src/components/AppFooter.vue +++ b/src/components/AppFooter.vue @@ -3,7 +3,6 @@ import { useSiteStore } from '@/stores/modules/site' const siteStore = useSiteStore() -// 设计稿快速导航列原文:首页 / 案例中心 / 需求提报 / 下载 APP / 帮助中心 const quickLinks = [ { label: '首页', path: '/' }, { label: '案例中心', path: '/cases' }, @@ -85,10 +84,6 @@ const coreBusiness = [ diff --git a/src/views/home/index.vue b/src/views/home/index.vue index d675cc4..63d6e14 100644 --- a/src/views/home/index.vue +++ b/src/views/home/index.vue @@ -2,7 +2,6 @@ diff --git a/src/views/message/cpns/MessageTabs.vue b/src/views/message/cpns/MessageTabs.vue index 749be9e..2de059b 100644 --- a/src/views/message/cpns/MessageTabs.vue +++ b/src/views/message/cpns/MessageTabs.vue @@ -47,21 +47,21 @@ function countOf(value: MessageType | 'all', counts: Counts): number { diff --git a/src/views/profile/cpns/ProfileSider.vue b/src/views/profile/cpns/ProfileSider.vue index 6f19102..52adf75 100644 --- a/src/views/profile/cpns/ProfileSider.vue +++ b/src/views/profile/cpns/ProfileSider.vue @@ -4,7 +4,6 @@ interface MenuItem { label: string } -// 设计稿(个人中心)菜单项 y268/304/340/376/412/448/484/520,行距 36,文字 x179(卡内缩进 24) const menus: MenuItem[] = [ { to: '/profile/security', label: '账号安全' }, { to: '/profile/address', label: '地址管理' }, @@ -31,7 +30,6 @@ const menus: MenuItem[] = [