Files
qitongxue-admin/README.md
2026-09-29 10:58:25 +08:00

2.2 KiB
Raw Blame History

工具百宝箱 · 管理后台(qitongxue-admin)

Vue 3 + Vite + ant-design-vue v4 + Tailwind 的运营管理端。

接口字段口径(重要 · 防回归)

三端(管理端 / 小程序 / 后端)共享一套契约冻结的字段口径,改代码时务必遵守:

方向 口径 说明
请求体(发出去) camelCase 如 levelKey / isEnabled / moduleKey / sortBy。后端结构体 tag 即 json:"levelKey"。
响应体(读回来) snake_case 如 level_key / is_enabled / module_key / usage_count / created_at / level_expire_at。

src/api/request.js 的响应拦截器不做任何大小写转换:code === 0 时直接 return result。 因此页面里读响应字段必须写 snake_case;写请求字段必须写 camelCase。

约定 S1 / S2(跨文件共享)

  • S1:管理端展示层只读响应 snake_case;请求体发 camelCase。不引入运行时自动转换层(会掩盖契约问题)。
  • S2:表单态(camel)与响应态(snake)之间必须显式映射:每页定义 toForm(record)(snake → camel)与 fromForm(form)(camel → 请求体)。 严禁 Object.assign(form, { ...record }) 这种展开式回填 —— record 是 snake,form.levelKey 会拿到 undefined,保存时把 level_key 清空。

基线参考

AdminManage.vue / AuditLog.vue / QueryLog.vue / ImportPreview.vue / EventList.vue / EnterpriseManage.vue 读 snake_case 是正确基线,请勿「顺手统一」为 camelCase。

示例

// 读响应(snake_case)
const res = await levelListApi()
modules.value = res?.list || []
modules.value.find((m) => m.module_key === key) // ✅
modules.value.find((m) => m.moduleKey === key)  // ❌ 永远 undefined

// 写请求(camelCase)+ 显式映射(S2)
function toForm(record) {
  return { id: record.id, levelKey: record.level_key, isEnabled: record.is_enabled }
}
function fromForm(f) {
  return { id: f.id, levelKey: f.levelKey, isEnabled: f.isEnabled }
}
await levelSaveApi(fromForm(form))

开发

pnpm install
pnpm run dev     # 本地开发
pnpm run build   # 生产构建