ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Vue3 还原一个企业级后台-10-模型标准发布

Vue3 还原一个企业级后台-10-模型标准发布 业务实现 3模型标准发布模块模型汇聚是收进来模型标准发布是放出去。这是三个业务模块的最后一环也是唯一涉及状态流转的模块——草稿、审核中、已发布、已下线四个状态组成一个标准的状态机。本文讲清楚状态机在前端怎么优雅实现。一、业务理解模型标准发布是什么管网模型工具的业务链路是模型汇聚 → 格式转换 → 标准发布 → API 注册 → 调试。上一篇做的模型汇聚处理了第一步这一篇处理的是第三步——把平台内部的 AI 模型封装成标准 API供外部系统调用。1.1 一句话区分三个模块模块管理对象方向核心交互API 注册管理后端已有的 API录入列表、筛选、调试模型汇聚AI 模型收进来列表、3 Tab 详情模型标准发布模型→API 的转换放出去列表、状态机、表单1.2 四种状态和它们之间的关系草稿 ──提交审核──→ 审核中 ──审核通过──→ 已发布 ↑ │ │ │ 撤回 │ │ └──────────────────┘ 下线 │ │ │ ↓ │ 已下线 ──重新发布──→ 草稿每个状态的操作权限状态可编辑可删除可撤回可下线可重新发布草稿✅✅❌❌❌审核中❌❌✅❌❌已发布❌❌❌✅❌已下线❌❌❌❌✅二、用常量定义状态机状态机最差的做法是用散落的if-else判断——代码里到处都是row.status published、row.status auditing改一个状态名要改十几处。最优的做法是把状态机定义为一个常量对象// constants/modelPublish.jsexportconstSTATUS{DRAFT:draft,AUDITING:auditing,PUBLISHED:published,OFFLINE:offline}exportconstSTATUS_MAP{[STATUS.DRAFT]:{label:草稿,color:#909399,// 灰色canEdit:true,canDelete:true,actions:[edit,delete,submit]// 可执行的操作},[STATUS.AUDITING]:{label:审核中,color:#E6A23C,// 橙色canEdit:false,canDelete:false,actions:[recall]// 只能撤回},[STATUS.PUBLISHED]:{label:已发布,color:#67C23A,// 绿色canEdit:false,canDelete:false,actions:[offline]// 只能下线},[STATUS.OFFLINE]:{label:已下线,color:#F56C6C,// 红色canEdit:false,canDelete:false,actions:[republish]// 只能重新发布}}// 状态流转规则哪些状态可以转到哪些状态exportconstTRANSITIONS{[STATUS.DRAFT]:[STATUS.AUDITING],[STATUS.AUDITING]:[STATUS.DRAFT,STATUS.PUBLISHED],[STATUS.PUBLISHED]:[STATUS.OFFLINE],[STATUS.OFFLINE]:[STATUS.DRAFT]}有了STATUS_MAP渲染状态标签时直接用template span classstatus-tag :style{ color: STATUS_MAP[row.status].color } {{ STATUS_MAP[row.status].label }} /span /template判断操作按钮是否显示template el-button v-ifSTATUS_MAP[row.status].canEdit typeprimary link clickeditRow(row)编辑/el-button el-button v-ifSTATUS_MAP[row.status].canDelete typedanger link clickdeleteRow(row)删除/el-button /template改一个状态名只需要改STATUS_MAP一个地方。这就是状态机工程化的核心价值。三、列表页状态驱动的操作列!-- views/model-publish/PublishList.vue -- template div classpage-card AppBreadcrumb :items[{ title: 模型标准发布 }] / div classfilter-bar el-select v-modelfilters.status placeholder状态 clearable stylewidth: 140px el-option v-fors in statusOptions :keys.value :labels.label :values.value / /el-select el-select v-modelfilters.modelType placeholder模型类型 clearable stylewidth: 140px el-option label算法模型 valuealgorithm / el-option label几何模型 valuegeometry / el-option label物理模型 valuephysics / el-option label规则模型 valuerule / /el-select AppSearchInput v-modelfilters.keyword placeholder搜索模型名称 searchonSearch / el-button typeprimary :iconPlus clickopenCreate新建发布/el-button /div AppTable :datatableData :columnscolumns :loadingloading :totaltotal v-model:pagepage page-changefetchData template #status{ row } span classstatus-tag :style{ color: STATUS_MAP[row.status]?.color } {{ STATUS_MAP[row.status]?.label }} /span /template template #action{ row } el-button v-ifSTATUS_MAP[row.status]?.canEdit typeprimary link clickeditRow(row)编辑/el-button el-button v-ifrow.status STATUS.AUDITING typewarning link clickrecall(row)撤回/el-button el-button v-ifrow.status STATUS.PUBLISHED typedanger link clickoffline(row)下线/el-button el-button v-ifrow.status STATUS.OFFLINE typesuccess link clickrepublish(row)重新发布/el-button /template /AppTable /div /templateconstcolumns[{prop:modelName,label:模型名称,width:200,align:left},{prop:modelType,label:模型类型,width:120,align:center},{prop:status,label:状态,width:120,align:center,slot:status},{prop:publishMethod,label:发布方式,width:140,align:center},{prop:updateTime,label:更新时间,width:180,align:center}]conststatusOptionsObject.entries(STATUS_MAP).map(([value,conf])({value,label:conf.label}))3.1 操作列是状态机的直接产物操作列的四个按钮不是硬编码的而是按STATUS_MAP定义的actions数组来渲染的。更优雅的做法是直接遍历actionstemplate #action{ row } template v-foraction in STATUS_MAP[row.status]?.actions :keyaction el-button v-ifaction edit typeprimary link clickeditRow(row)编辑/el-button el-button v-ifaction delete typedanger link clickdeleteRow(row)删除/el-button el-button v-ifaction submit typesuccess link clickhandleSubmit(row)提交审核/el-button el-button v-ifaction recall typewarning link clickrecall(row)撤回/el-button el-button v-ifaction offline typedanger link clickoffline(row)下线/el-button el-button v-ifaction republish typesuccess link clickrepublish(row)重新发布/el-button /template /template这样新增一个状态时只需在STATUS_MAP里加一行操作列自动生成按钮。四、详情页基本信息 发布操作模型标准发布的详情页和 API 管理的详情页结构相同但内容不同——它展示的是模型的基本信息 发布按钮。!-- views/model-publish/PublishDetail.vue -- template div classpage-card div classdetail-header el-button :iconArrowLeft text clickgoBack返回/el-button AppBreadcrumb :items[ { title: 模型标准发布, path: /model-publish }, { title: detail.modelName } ] / /div el-descriptions :column2 border stylemargin-top: 16px el-descriptions-item label模型名称{{ detail.modelName }}/el-descriptions-item el-descriptions-item label模型类型{{ detail.modelType }}/el-descriptions-item el-descriptions-item label发布方式{{ detail.publishMethod }}/el-descriptions-item el-descriptions-item label协议{{ detail.protocol }}/el-descriptions-item el-descriptions-item label鉴权方式{{ detail.authMethod }}/el-descriptions-item el-descriptions-item label状态 span :style{ color: STATUS_MAP[detail.status]?.color } {{ STATUS_MAP[detail.status]?.label }} /span /el-descriptions-item el-descriptions-item label创建时间{{ detail.createTime }}/el-descriptions-item el-descriptions-item label接口地址 :span2 code{{ detail.apiUrl }}/code /el-descriptions-item /el-descriptions !-- 发布按钮区 -- div classpublish-actions stylemargin-top: 24px; text-align: right el-button v-ifSTATUS_MAP[detail.status]?.canEdit typeprimary clickeditDetail编辑/el-button el-button v-ifdetail.status STATUS.DRAFT typesuccess clickopenPublishDialog提交审核/el-button el-button v-ifdetail.status STATUS.AUDITING typewarning clickrecall撤回/el-button el-button v-ifdetail.status STATUS.PUBLISHED typedanger clickoffline下线/el-button el-button v-ifdetail.status STATUS.OFFLINE typesuccess clickrepublish重新发布/el-button /div /div /template4.1 状态流转的函数实现每个操作按钮背后是一个函数它们的共同模式是弹确认 → 调接口 → 刷新状态。import{ElMessage,ElMessageBox}fromelement-plus// 提交审核草稿 → 审核中asyncfunctionhandleSubmit(row){awaitElMessageBox.confirm(确认将「${row.modelName}」提交审核提交后将不可编辑。,提交审核,{type:warning})awaittransitionStatus(row.id,submit)ElMessage.success(已提交审核)fetchData()}// 撤回审核中 → 草稿asyncfunctionrecall(row){awaitElMessageBox.confirm(确认撤回「${row.modelName}」的审核撤回后状态恢复为草稿。,撤回审核,{type:warning})awaittransitionStatus(row.id,recall)ElMessage.success(已撤回)fetchData()}// 下线已发布 → 已下线asyncfunctionoffline(row){awaitElMessageBox.confirm(确认下线「${row.modelName}」下线后外部将无法调用该 API。,下线确认,{type:warning,confirmButtonText:确认下线,confirmButtonClass:el-button--danger})awaittransitionStatus(row.id,offline)ElMessage.success(已下线)fetchData()}// 重新发布已下线 → 草稿asyncfunctionrepublish(row){awaitElMessageBox.confirm(确认重新发布「${row.modelName}」将创建新的草稿。,重新发布,{type:info})awaittransitionStatus(row.id,republish)ElMessage.success(已创建新草稿)fetchData()}注意两个细节下线操作的confirmButtonClass设了el-button--danger——红色按钮提醒用户这是破坏性操作。transitionStatus是统一的接口——后端只需要一个接口处理所有状态变更前端传action即可。这在原型阶段用 Mock 拦截器模拟真实接口只需把 Mock 替掉。五、发布弹窗提交审核的最后一步从草稿提交审核时需要一个弹窗填写发布信息!-- views/model-publish/PublishDialog.vue -- template AppDialog v-modelvisible title提交发布 width520px :loadingsubmitting confirmconfirmPublish el-form refformRef :modelform :rulesrules label-width100px el-form-item label发布渠道 propchannel el-select v-modelform.channel stylewidth: 100% el-option label管网平台 API 网关 valuepipe-gateway / el-option label统一 API 市场 valueapi-market / el-option label内部调度引擎 valueinternal-scheduler / /el-select /el-form-item el-form-item label版本号 propversion el-input v-modelform.version placeholder例如v2.1.0 / /el-form-item el-form-item label发布说明 el-input v-modelform.notes typetextarea :rows3 placeholder本次发布的更新内容... / /el-form-item el-alert v-ifshowProgress title审核进度 typesuccess :closablefalse show-icon stylemargin-top: 12px template #default el-steps directionvertical :activeprogressStep stylemargin-top: 8px el-step title校验模型文件完整性 / el-step title生成 API 文档 / el-step title注册到网关 / el-step title审核完成 / /el-steps /template /el-alert /el-form /AppDialog /templateconstformreactive({channel:pipe-gateway,version:,notes:})construles{channel:[{required:true,message:请选择发布渠道,trigger:change}],version:[{required:true,message:请输入版本号,trigger:blur}]}constshowProgressref(false)constprogressStepref(0)asyncfunctionconfirmPublish(){awaitformRef.value.validate()submitting.valuetrueshowProgress.valuetrue// 模拟审核进度原型演示用for(leti0;i3;i){progressStep.valueiawaitnewPromise(rsetTimeout(r,600))}awaitpublishModel({id:props.modelId,...form})ElMessage.success(已提交审核)visible.valuefalseemit(success)}发布弹窗最出彩的是审核进度模拟——el-steps垂直方向一步步点亮客户看到后对发布流程的理解从抽象变具体。原型之所以叫原型就是因为它能把流程可视化。六、完整的发布流程把上面的列表页、详情页、弹窗串起来就是模型标准发布的完整流程1. 创建草稿新建发布 ↓ 2. 填写基本信息协议、鉴权方式、接口配置 ↓ 3. 提交审核填写发布渠道、版本号、发布说明 → 状态变为审核中 ↓ 4. 审核通过演示时手动模拟 → 状态变为已发布 ↓ 5. 下线不再维护 → 状态变为已下线 ↓ 6. 重新发布创建新草稿重新走流程在原型阶段审核通过是手动触发的——前端 Mock 拦截器直接返回status: published。真实项目中这一步由后端审核系统回调完成前端只需要正确展示状态即可。七、与 API 注册管理的业务关系很多读者会混淆这两个模块这里做一个清晰的对比维度模型标准发布API 注册管理管理对象AI 模型后端 API输入平台内部的模型后端已存在的 API产出标准 APIN/A只是登记核心流程草稿→审核→发布新增→编辑→调试状态数量4 种带状态机2 种启用/禁用复杂度⭐⭐⭐⭐⭐在业务链路上它们是上下游关系模型汇聚收模型 → 模型标准发布模型→API → API 注册管理登记 API → 调试调用测试但技术上它们是平级模块共用同一套列表页范式 AppTable AppDialog。前面几篇打下的基础到了这一篇只用 30% 的代码就完成了 70% 的业务逻辑。八、状态机工程化的三个原则模型标准发布模块做完沉淀出状态机工程化的三个原则1. 状态常量化。不要散落字符串draft、published全部定义在STATUS常量里。改一个字面量只改一处。2. 配置驱动 UI。标签颜色、操作按钮、可编辑性全部从STATUS_MAP配置读取不写死。新增一个状态时代码几乎不需要改。3. 所有状态变更走统一入口。transitionStatus(id, action)一个函数处理全部状态流转前端不直接改row.status。这让 Mock 阶段和真实接口阶段的切换成本降到零——换个 axios 地址即可。这三条原则不仅适用于模型标准发布任何带状态流转的模块订单、审批、工单都可以复用。上一篇09 - 业务实现 2模型汇聚模块3 Tab 详情下一篇预告三个业务模块都写完了但它们的数据都是假的。下一篇讲怎么用 mockjs axios 拦截器让 75 条假数据看起来像真的——名称不重复、时间有分布、状态有逻辑、字段有关联。
返回列表