]> acesimba.cloud Git - StationBuilder-vue.git/commitdiff
领域方案维护弹框:按 web-ui-builder 规范重构 UI 并支持编辑方案字段
authorroot <root@localhost.localdomain>
Mon, 28 Sep 2026 06:38:46 +0000 (14:38 +0800)
committerroot <root@localhost.localdomain>
Mon, 28 Sep 2026 06:38:46 +0000 (14:38 +0800)
- 弹框改为 dlg-box/UiOverlay 结构:480px 宽、24px 内边距、22px 标题「维护领域方案」
- 支持编辑:方案名称/缩写(英文大写,自动转大写并校验)/所属领域(下拉)/版本号/状态(可用、编辑中)/方案说明(多行)
- 缺失字段不通过校验时禁用保存;详情页状态标签支持「编辑中」
- ui-system.css 将 field/field-label/button 规则扩展到 domain-maintain-dialog,必填标记红色

src-vue/pages/domain/DomainCapabilityDetail.vue
src-vue/styles/ui-system.css

index a0ef2cdf2df8f89034c7f7fee52d0f42b2686277..d4c660bbdaa033b9402d6bcad97e46f1d86daa7e 100644 (file)
@@ -3,6 +3,7 @@ import { ref, computed, watch, onMounted } from "vue";
 import { ElTag } from "element-plus";
 import { OfficeBuilding, Close, Aim, DocumentCopy, MoreFilled, Upload, Plus, Edit, Download, Link, View } from "@element-plus/icons-vue";
 import UiButton from "../../ui/UiButton.vue";
+import UiInput from "../../ui/UiInput.vue";
 import UiSelect from "../../ui/UiSelect.vue";
 import UiTable from "../../ui/UiTable.vue";
 import UiActions from "../../ui/UiActions.vue";
@@ -61,6 +62,7 @@ async function load() {
     draft.value = {
       domain_id: d.domain_id,
       name: d.name || "",
+      abbr: d.abbr || "",
       version: d.version || "1.0",
       status: d.status || "available",
       description: d.description || "",
@@ -76,11 +78,13 @@ async function load() {
 onMounted(load);
 
 async function saveMeta() {
+  if (!draft.value.name.trim()) { props.notify("请填写方案名称"); return; }
+  if (!/^[A-Z]+$/.test((draft.value.abbr || "").trim())) { props.notify("缩写必须为英文大写字母"); return; }
   try {
     await fetchDb(`/domain-templates/${props.id}`, {
       method: "PUT",
       headers: { "Content-Type": "application/json" },
-      body: JSON.stringify(draft.value),
+      body: JSON.stringify({ ...draft.value, name: draft.value.name.trim(), abbr: (draft.value.abbr || "").trim() }),
     });
     props.notify("方案信息已保存");
     editing.value = false;
@@ -180,7 +184,7 @@ function editHandler(card) {
       <section :class="['domain-capability-head', scene.tone]">
         <div class="domain-capability-code">{{ scene.code }}</div>
         <div class="domain-capability-copy">
-          <div><ElTag class="tag-new" :class="'tag-' + domainTagColor(domainName)">{{ domainName }}</ElTag><Status>{{ detail.status === "available" ? "可用" : "不可用" }}</Status><span>版本 {{ detail.version || "1.0" }}</span></div>
+          <div><ElTag class="tag-new" :class="'tag-' + domainTagColor(domainName)">{{ domainName }}</ElTag><Status>{{ detail.status === "available" ? "可用" : detail.status === "editing" ? "编辑中" : "不可用" }}</Status><span>版本 {{ detail.version || "1.0" }}</span></div>
           <h2>{{ detail.name || "未命名领域方案" }}</h2>
           <p>{{ detail.description || scene.desc }}</p>
         </div>
@@ -334,32 +338,42 @@ function editHandler(card) {
       </div>
     </UiOverlay>
 
-    <UiOverlay v-if="editing && draft" class="modal-backdrop" @mousedown="() => (editing = false)">
-      <div class="modal domain-maintain-modal" @mousedown.stop>
-        <header><h2>维护领域方案</h2><UiButton @click="() => (editing = false)">×</UiButton></header>
-        <div class="modal-body">
-          <div class="form-grid">
-            <Field label="方案名称" required><UiInput :value="draft.name" @change="(e) => (draft = { ...draft, name: e.target.value })" /></Field>
-            <Field label="所属领域" required>
-              <UiSelect :value="draft.domain_id" @change="(e) => (draft = { ...draft, domain_id: Number(e.target.value) })">
-                <option v-for="d in doms" :key="d.id" :value="d.id">{{ friendlyDomainName(d.name) }}</option>
-              </UiSelect>
-            </Field>
-            <Field label="版本"><UiInput :value="draft.version" @change="(e) => (draft = { ...draft, version: e.target.value })" /></Field>
-            <Field label="状态">
-              <UiSelect :value="draft.status" @change="(e) => (draft = { ...draft, status: e.target.value })">
-                <option value="available">可用</option>
-                <option value="unavailable">不可用</option>
-              </UiSelect>
-            </Field>
-            <Field label="方案说明"><UiInput textarea :rows="4" :value="draft.description" @change="(e) => (draft = { ...draft, description: e.target.value })" /></Field>
-          </div>
-          <div class="domain-maintain-note">资产、页面、知识与菜单均可分别进入预览后维护;本页不再采用分步确认流程。</div>
-        </div>
-        <footer>
+    <UiOverlay v-if="editing && draft" className="dlg-backdrop" @mousedown="() => (editing = false)">
+      <div class="dlg-box domain-maintain-dialog" style="width:480px" @mousedown.stop>
+        <h2>维护领域方案</h2>
+        <label class="field">
+          <span class="field-label"><i class="req">*</i>方案名称</span>
+          <UiInput :value="draft.name" maxLength="20" placeholder="请输入方案名称" @change="(e) => (draft = { ...draft, name: e.target.value })" />
+        </label>
+        <label class="field">
+          <span class="field-label"><i class="req">*</i>缩写(英文大写)</span>
+          <UiInput :value="draft.abbr" maxLength="10" placeholder="如 WTP" @change="(e) => (draft = { ...draft, abbr: e.target.value.toUpperCase() })" />
+        </label>
+        <label class="field">
+          <span class="field-label"><i class="req">*</i>所属领域</span>
+          <UiSelect :value="draft.domain_id" @change="(e) => (draft = { ...draft, domain_id: Number(e.target.value) })">
+            <option v-for="d in doms" :key="d.id" :value="d.id">{{ friendlyDomainName(d.name) }}</option>
+          </UiSelect>
+        </label>
+        <label class="field">
+          <span class="field-label">版本号</span>
+          <UiInput :value="draft.version" placeholder="如 V1.0" @change="(e) => (draft = { ...draft, version: e.target.value })" />
+        </label>
+        <label class="field">
+          <span class="field-label">状态</span>
+          <UiSelect :value="draft.status" @change="(e) => (draft = { ...draft, status: e.target.value })">
+            <option value="available">可用</option>
+            <option value="editing">编辑中</option>
+          </UiSelect>
+        </label>
+        <label class="field">
+          <span class="field-label">方案说明</span>
+          <UiInput textarea :rows="4" :value="draft.description" placeholder="请输入方案说明" @change="(e) => (draft = { ...draft, description: e.target.value })" />
+        </label>
+        <UiActions className="dlg-actions">
           <ElButton secondary @click="() => (editing = false)">取消</ElButton>
-          <ElButton @click="saveMeta">保存</ElButton>
-        </footer>
+          <ElButton :disabled="!draft.name.trim() || !/^[A-Z]+$/.test((draft.abbr || '').trim())" @click="saveMeta">保存</ElButton>
+        </UiActions>
       </div>
     </UiOverlay>
 
index d9ae096d6873847fd0b8cf03c1880d1152267d50..81e4da0926cf2a76c9abf06aee0f2d7937829dcf 100644 (file)
@@ -95,8 +95,10 @@ html,body{font-family:var(--ant-font-family);font-size:var(--ant-font-size);colo
 /* 领域配置:默认颜色配置(swatch / dot),复用 antd 预设色板(web-ui-builder 设计体系) */
 .domain-color-dot{display:inline-block;width:10px;height:10px;border-radius:50%;margin-right:8px;vertical-align:middle;border:1px solid color-mix(in srgb,var(--ant-color-text-base) 10%,transparent)}
 .domain-color-dot.tag-blue{background:#1677ff}.domain-color-dot.tag-cyan{background:#13c2c2}.domain-color-dot.tag-orange{background:#fa8c16}.domain-color-dot.tag-green{background:#52c41a}.domain-color-dot.tag-purple{background:#722ed1}.domain-color-dot.tag-red{background:#f5222d}.domain-color-dot.tag-default{background:#8c8c8c}
-.domain-edit-dialog .field,.domain-create-dialog .field{display:block;margin-bottom:16px}
-.domain-edit-dialog .field-label,.domain-create-dialog .field-label{display:block;font-size:var(--ant-font-size-sm);color:var(--ant-color-text-secondary);margin-bottom:6px}
+.domain-edit-dialog .field,.domain-create-dialog .field,.domain-maintain-dialog .field{display:block;margin-bottom:16px}
+.domain-edit-dialog .field-label,.domain-create-dialog .field-label,.domain-maintain-dialog .field-label{display:block;font-size:var(--ant-font-size-sm);color:var(--ant-color-text-secondary);margin-bottom:6px}
+.field-label .req{color:var(--ant-color-error);font-style:normal;margin-right:4px}
+.domain-edit-dialog .button,.domain-create-dialog .button,.domain-maintain-dialog .button{min-width:96px;margin:0}
 .domain-color-picker{display:flex;gap:10px;flex-wrap:wrap}
 .domain-color-swatch{width:28px;height:28px;border-radius:var(--ant-border-radius);border:1px solid var(--ant-color-border);cursor:pointer;padding:0;transition:box-shadow .15s}
 .domain-color-swatch.tag-blue{background:#1677ff}.domain-color-swatch.tag-cyan{background:#13c2c2}.domain-color-swatch.tag-orange{background:#fa8c16}.domain-color-swatch.tag-green{background:#52c41a}.domain-color-swatch.tag-purple{background:#722ed1}.domain-color-swatch.tag-red{background:#f5222d}.domain-color-swatch.tag-default{background:#8c8c8c}