# 参考:前端框架差异对照 > 前端 UI 适配时加载此文档。 > **核心原则**:逐行阅读理解后修改,不要机械式查找替换。 --- ## script 部分差异 | CRM 原版 | shanxia2.0 等价方式 | 说明 | |----------|---------------------|------| | `getCurrentInstance()` + `proxy` | 删除 | shanxia2.0 不使用 proxy | | `proxy?.useDict('xxx')` | `useDictTag('xxx')` 或 `dictStore.getLabel()` | 字典获取 | | `proxy?.$modal.msgSuccess(msg)` | `ElMessage.success(msg)` | 成功提示 | | `proxy?.$modal.msgWarning(msg)` | `ElMessage.warning(msg)` | 警告提示 | | `proxy?.$modal.msgError(msg)` | `ElMessage.error(msg)` | 错误提示 | | `proxy?.$modal.confirm(msg)` | `ElMessageBox.confirm(msg, '提示', { type: 'warning' })` | 确认框 | | `import { ElMessage } from 'element-plus'` | 删除 | 自动导入 | | `import { ref, reactive } from 'vue'` | 删除 | 自动导入 | | `request({ url, method, data })` | `request.post('/web/crm/xxx', data)` | API 调用 | | `hasPermi(['crm:xxx:add'])` | `v-auth="'add'"` | 权限 | ## API 响应数据处理(重要) `request.post` 已在拦截器中解包 `res.data.data`,返回值直接是 API 的 `data` 字段内容。 但由于加密/非加密场景差异,返回结构不完全一致,**必须使用兼容写法**: ```js // ✅ 正确:兼容写法 const res = await fetchXxxList(params) const data = (res as any)?.data || res || {} list.value = data.list || data.rows || [] pagination.total = data.total ?? 0 // ❌ 错误:多套一层 .data const res = await fetchXxxList(params) const list = res.data?.list // undefined! ``` **下拉选择器加载用户列表**: - `pageSize` 上限为 100(后端 `Query(le=100)`),传 `1000` 会 422 - 用 `pageSize: 100` + `filterable` 搜索过滤 - 选项字段为 **`label` / `value`**(`fetchUserOptions`),勿用原 CRM 的 `nickName` / `userId` ## Excel / Blob 导出(重要) CRM 列表「导出」走 `responseType: 'blob'`,已在 `src/utils/http/index.ts` 集中适配: ```ts // api/crm/xxx/index.ts export function exportXxx(query?: XxxQuery) { return request.post({ url: `${BASE}/export`, data: mapListQuery(query), responseType: 'blob', showErrorMessage: false }) } ``` ```ts // 页面 handleExport const res = await exportXxx(params) const blob = res instanceof Blob ? res : new Blob([res as BlobPart], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }) // ... createObjectURL + link.click() ``` - 拦截器对 xlsx **不**做 JSON `code` 校验;对 JSON 错误体(如缺少 openpyxl)仍会解析并抛错 - 后端字典列已由 `crm_export_columns.py` + `excel_export.py` 翻译,前端无需再转 label ## 查看详情(SystemViewDialog) | CRM 原版 | shanxia2.0 | |----------|------------| | `` 宽抽屉 + Tab | ``(参考 `clue/detailDrawer.vue`) | | 抽屉内 `` | `ViewField` + `tagType` + `dictStore.getLabel()` | 打开详情前:`await dictStore.loadAllDict()`(避免字典 code 直出)。 ## template 部分差异 | CRM 原版 | shanxia2.0 等价方式 | 说明 | |----------|---------------------|------| | `` | `` | 禁止抽屉,统一弹窗 | | `` | `` | 固定宽度 | | `` | `{{ getLabel(val) }}` | 字典展示 | | `` | `
` | 工具栏 | | `label-width="120px"` | `label-position="top"` | 表单标签 | | `` 栅格 | `.dialog-form-layout` + `.form-grid-2` | 表单布局 | | RuoYi 上传组件 | MinIO `fetchUploadAttachment` | 文件上传 | ## 弹窗标准模板 ```vue
``` ## style 部分差异 - UnoCSS 工具类 → Tailwind CSS 等价类 - 复杂样式用 SCSS - 使用门户标准 CSS 类:`dialog-form-layout`、`form-grid-2`、`form-col-span-2` ## 详细对照规则 完整的 1044 行替换规则见 `docs/crm-frontend-migration-guide.md`。