Files
shanxia2.0/docs/crm-migration/ref-frontend-diff.md
T
2026-06-01 08:21:21 +08:00

4.7 KiB
Raw Blame History

参考:前端框架差异对照

前端 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 字段内容。 但由于加密/非加密场景差异,返回结构不完全一致,必须使用兼容写法:

// ✅ 正确:兼容写法
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 集中适配:

// api/crm/xxx/index.ts
export function exportXxx(query?: XxxQuery) {
  return request.post({
    url: `${BASE}/export`,
    data: mapListQuery(query),
    responseType: 'blob',
    showErrorMessage: false
  })
}
// 页面 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
<el-drawer> 宽抽屉 + Tab <SystemViewDialog>(参考 clue/detailDrawer.vue)
抽屉内 <dict-tag> ViewField + tagType + dictStore.getLabel()

打开详情前:await dictStore.loadAllDict()(避免字典 code 直出)。

template 部分差异

CRM 原版 shanxia2.0 等价方式 说明
<el-drawer> <el-dialog> 禁止抽屉,统一弹窗
<el-drawer size="80%"> <el-dialog width="960px"> 固定宽度
<dict-tag :options="xxx" :value="val"/> <el-tag :type="getTagType(val)" size="small">{{ getLabel(val) }}</el-tag> 字典展示
<right-toolbar> <div class="list-toolbar"><div class="list-toolbar-row"> 工具栏
label-width="120px" label-position="top" 表单标签
<el-row><el-col :span="12"> 栅格 .dialog-form-layout + .form-grid-2 表单布局
RuoYi 上传组件 MinIO fetchUploadAttachment 文件上传

弹窗标准模板

<el-dialog v-model="innerVisible" :title="isEdit ? '编辑' : '新增'" width="960px"
  destroy-on-close align-center :close-on-click-modal="false"
  style="backdrop-filter: none" class="dialog-form-layout">
  <el-form ref="formRef" :model="formData" :rules="formRules"
    label-position="top" scroll-to-error
    :scroll-into-view-options="{ behavior: 'smooth', block: 'center' }">
    <div class="form-grid-2">
      <!-- 表单项 -->
    </div>
  </el-form>
  <template #footer>
    <el-button @click="innerVisible = false"><el-icon><Close /></el-icon>取消</el-button>
    <el-button type="primary" @click="handleSubmit"><el-icon><Check /></el-icon>确定</el-button>
  </template>
</el-dialog>

style 部分差异

  • UnoCSS 工具类 → Tailwind CSS 等价类
  • 复杂样式用 SCSS
  • 使用门户标准 CSS 类:dialog-form-layout、form-grid-2、form-col-span-2

详细对照规则

完整的 1044 行替换规则见 docs/crm-frontend-migration-guide.md。