优化前端提示文案与宽表滚动体验
This commit is contained in:
parent
6dd9529a16
commit
ac18942a4b
@ -187,7 +187,6 @@
|
|||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">AI 助手</p>
|
<p class="eyebrow">AI 助手</p>
|
||||||
<h3>百华工艺助手</h3>
|
<h3>百华工艺助手</h3>
|
||||||
<p>当前为内置占位对话,真实 LLM 可在 08 系统拓展中配置。</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button class="ghost-button" type="button" @click="closeAssistantDrawer">关闭</button>
|
<button class="ghost-button" type="button" @click="closeAssistantDrawer">关闭</button>
|
||||||
@ -251,7 +250,6 @@
|
|||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">管理员操作</p>
|
<p class="eyebrow">管理员操作</p>
|
||||||
<h3>重置他人密码</h3>
|
<h3>重置他人密码</h3>
|
||||||
<p>用于协助其他用户忘记密码时重置登录密码,仅系统管理员可用。</p>
|
|
||||||
</div>
|
</div>
|
||||||
<button class="ghost-button" type="button" @click="closePasswordModals">关闭</button>
|
<button class="ghost-button" type="button" @click="closePasswordModals">关闭</button>
|
||||||
</header>
|
</header>
|
||||||
@ -1202,7 +1200,7 @@ function sendAssistantMessage() {
|
|||||||
chatMessages.value.push({
|
chatMessages.value.push({
|
||||||
id: Date.now() + 1,
|
id: Date.now() + 1,
|
||||||
role: "assistant",
|
role: "assistant",
|
||||||
content: "我已收到。当前聊天窗口已就绪,后续在 08 系统拓展配置 LLM API 后,可以把这里切换为真实模型回复。现在我可以先作为操作入口,帮助你记录和梳理 ERP 问题。"
|
content: "已收到。"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
15
frontend/src/components/FormDrawer.test.js
Normal file
15
frontend/src/components/FormDrawer.test.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import assert from "node:assert/strict";
|
||||||
|
import { describe, it } from "node:test";
|
||||||
|
import { readFileSync } from "node:fs";
|
||||||
|
import { dirname, join } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
const source = readFileSync(join(__dirname, "FormDrawer.vue"), "utf8");
|
||||||
|
|
||||||
|
describe("FormDrawer copy discipline", () => {
|
||||||
|
it("does not render description copy as an always-visible header paragraph", () => {
|
||||||
|
assert.doesNotMatch(source, /class="form-drawer-description"/);
|
||||||
|
assert.doesNotMatch(source, /aria-describedby="description/);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -1,14 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<Teleport to="body">
|
<Teleport to="body">
|
||||||
<div v-if="open" class="workflow-drawer-mask" @click.self="emit('close')">
|
<div v-if="open" class="workflow-drawer-mask" @click.self="emit('close')">
|
||||||
<aside class="workflow-drawer form-drawer" :class="drawerClass" :aria-describedby="description ? descriptionId : undefined">
|
<aside class="workflow-drawer form-drawer" :class="drawerClass">
|
||||||
<header class="workflow-drawer-head">
|
<header class="workflow-drawer-head">
|
||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">{{ eyebrow }}</p>
|
<p class="eyebrow">{{ eyebrow }}</p>
|
||||||
<div class="drawer-title-row" :title="description || undefined">
|
<div class="drawer-title-row">
|
||||||
<h3>{{ title }}</h3>
|
<h3>{{ title }}</h3>
|
||||||
</div>
|
</div>
|
||||||
<p v-if="description" :id="descriptionId" class="form-drawer-description">{{ description }}</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="workflow-drawer-head-actions">
|
<div class="workflow-drawer-head-actions">
|
||||||
<span v-if="tag" class="panel-tag">{{ tag }}</span>
|
<span v-if="tag" class="panel-tag">{{ tag }}</span>
|
||||||
@ -27,7 +26,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, toRef, useId } from "vue";
|
import { computed, toRef } from "vue";
|
||||||
|
|
||||||
import { useBodyScrollLock } from "../composables/useBodyScrollLock";
|
import { useBodyScrollLock } from "../composables/useBodyScrollLock";
|
||||||
import AppIcon from "./AppIcon.vue";
|
import AppIcon from "./AppIcon.vue";
|
||||||
@ -64,7 +63,6 @@ const props = defineProps({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const emit = defineEmits(["close"]);
|
const emit = defineEmits(["close"]);
|
||||||
const descriptionId = `form-drawer-description-${useId()}`;
|
|
||||||
|
|
||||||
const drawerClass = computed(() => {
|
const drawerClass = computed(() => {
|
||||||
const normalizedSize = ["normal", "wide", "xl", "fullscreen"].includes(props.size) ? props.size : "normal";
|
const normalizedSize = ["normal", "wide", "xl", "fullscreen"].includes(props.size) ? props.size : "normal";
|
||||||
|
|||||||
@ -36,7 +36,7 @@
|
|||||||
<p class="eyebrow">组织人员</p>
|
<p class="eyebrow">组织人员</p>
|
||||||
<h3>{{ selectedNodeLabel }}</h3>
|
<h3>{{ selectedNodeLabel }}</h3>
|
||||||
<p class="node-manager-line" :title="selectedNodeManagerText">{{ selectedNodeManagerText }}</p>
|
<p class="node-manager-line" :title="selectedNodeManagerText">{{ selectedNodeManagerText }}</p>
|
||||||
<p class="permission-note">当前节点人员共 {{ selectedEmployees.length }} 人</p>
|
<span class="status-pill employee-count-pill">人员 {{ selectedEmployees.length }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="employee-head-actions">
|
<div class="employee-head-actions">
|
||||||
<button
|
<button
|
||||||
@ -583,13 +583,16 @@ function removeEmployee(employee) {
|
|||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.permission-note,
|
|
||||||
.empty-state {
|
.empty-state {
|
||||||
margin: 6px 0 0;
|
margin: 6px 0 0;
|
||||||
color: #64748b;
|
color: #64748b;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.employee-count-pill {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
.status-pill {
|
.status-pill {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@ -48,10 +48,7 @@
|
|||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">步骤一</p>
|
<p class="eyebrow">步骤一</p>
|
||||||
<span
|
<span class="title-with-help">
|
||||||
class="title-with-help"
|
|
||||||
title="同一产品编码允许维护多个版本。编辑时如果修改版本号,系统会自动保存成新版本。"
|
|
||||||
>
|
|
||||||
<h3>产品资料</h3>
|
<h3>产品资料</h3>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -174,7 +171,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div v-if="!suppliers.length" class="workflow-empty-card">还没有供应商,请先新增供应商。</div>
|
<div v-if="!suppliers.length" class="workflow-empty-card">暂无供应商</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form v-if="showSupplierCreateForm" class="stack-form workflow-inline-form" @submit.prevent="createSupplier">
|
<form v-if="showSupplierCreateForm" class="stack-form workflow-inline-form" @submit.prevent="createSupplier">
|
||||||
@ -276,9 +273,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<div v-if="!filteredMaterials.length" class="workflow-empty-card">
|
<div v-if="!filteredMaterials.length" class="workflow-empty-card">暂无可选原材料</div>
|
||||||
当前没有可选原材料,请先新建原材料或先勾选供应商。
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form v-if="showMaterialCreateForm" class="stack-form workflow-inline-form" @submit.prevent="createMaterial">
|
<form v-if="showMaterialCreateForm" class="stack-form workflow-inline-form" @submit.prevent="createMaterial">
|
||||||
@ -398,7 +393,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="!currentProductId" class="workflow-empty-card">请先在步骤一保存产品资料,再维护该产品的 BOM。</div>
|
<div v-if="!currentProductId" class="workflow-empty-card">保存产品后维护 BOM</div>
|
||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="table-wrap">
|
<div class="table-wrap">
|
||||||
@ -547,14 +542,14 @@
|
|||||||
<div class="panel-header">
|
<div class="panel-header">
|
||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">步骤五</p>
|
<p class="eyebrow">步骤五</p>
|
||||||
<span class="title-with-help" title="工艺路线只绑定当前产品版本,参考节拍用于后续和真实报工节拍对比。">
|
<span class="title-with-help">
|
||||||
<h3>工艺路线</h3>
|
<h3>工艺路线</h3>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<button class="ghost-button" type="button" :disabled="!currentProductId" @click="resetRouteForm">新建工艺路线</button>
|
<button class="ghost-button" type="button" :disabled="!currentProductId" @click="resetRouteForm">新建工艺路线</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="!currentProductId" class="workflow-empty-card">请先在步骤一保存产品资料,再维护该产品的工艺路线。</div>
|
<div v-if="!currentProductId" class="workflow-empty-card">保存产品后维护工艺路线</div>
|
||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div class="table-wrap">
|
<div class="table-wrap">
|
||||||
|
|||||||
@ -36,7 +36,6 @@
|
|||||||
<div class="stocktake-action-card stocktake-action-card-wide">
|
<div class="stocktake-action-card stocktake-action-card-wide">
|
||||||
<span class="stocktake-stage-tag">当前仓库:{{ currentWarehouseName }}</span>
|
<span class="stocktake-stage-tag">当前仓库:{{ currentWarehouseName }}</span>
|
||||||
<strong>01 确认盘库并导出仓库清单</strong>
|
<strong>01 确认盘库并导出仓库清单</strong>
|
||||||
<p>点击后系统会锁定当前仓库,并导出本次盘库 Excel 清单。盘库结束前该仓库不能出入库。</p>
|
|
||||||
<div class="stocktake-inline-actions">
|
<div class="stocktake-inline-actions">
|
||||||
<button class="primary-button" type="button" :disabled="busy || !currentWarehouseId" @click="startAndExportStocktake">
|
<button class="primary-button" type="button" :disabled="busy || !currentWarehouseId" @click="startAndExportStocktake">
|
||||||
{{ busy ? "处理中..." : "确认盘库并导出仓库清单" }}
|
{{ busy ? "处理中..." : "确认盘库并导出仓库清单" }}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|||||||
const styles = readFileSync(join(__dirname, "main.css"), "utf8");
|
const styles = readFileSync(join(__dirname, "main.css"), "utf8");
|
||||||
const viewSourceByName = new Map(
|
const viewSourceByName = new Map(
|
||||||
[
|
[
|
||||||
"InventoryLedgerView.vue",
|
"ProductSpecLiteView.vue",
|
||||||
"PurchaseOrderView.vue",
|
"PurchaseOrderView.vue",
|
||||||
"SalesPlanningView.vue",
|
"SalesPlanningView.vue",
|
||||||
"SupplierMaterialLiteView.vue",
|
"SupplierMaterialLiteView.vue",
|
||||||
@ -36,6 +36,15 @@ describe("table action button layout and tones", () => {
|
|||||||
assert.match(wideActionHeaderRule, /text-align:\s*center !important;/);
|
assert.match(wideActionHeaderRule, /text-align:\s*center !important;/);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("makes wide mode expose an explicit horizontal scrollbar for every table wrapper", () => {
|
||||||
|
const wideModeRule = cssRuleBlock("body .table-view-wide");
|
||||||
|
|
||||||
|
assert.match(wideModeRule, /overflow-x:\s*scroll !important;/);
|
||||||
|
assert.match(wideModeRule, /overflow-y:\s*hidden !important;/);
|
||||||
|
assert.match(wideModeRule, /scrollbar-gutter:\s*stable/);
|
||||||
|
assert.match(styles, /body \.table-view-wide::-webkit-scrollbar/);
|
||||||
|
});
|
||||||
|
|
||||||
it("centers compact overview action headers over icon-only action buttons", () => {
|
it("centers compact overview action headers over icon-only action buttons", () => {
|
||||||
const overviewActionHeaderRule = cssRuleBlock("body .table-view-overview .data-table:has(td.action-row) thead th:last-child");
|
const overviewActionHeaderRule = cssRuleBlock("body .table-view-overview .data-table:has(td.action-row) thead th:last-child");
|
||||||
|
|
||||||
|
|||||||
@ -11585,7 +11585,30 @@ body .table-cell-hover-tooltip-visible {
|
|||||||
}
|
}
|
||||||
|
|
||||||
body .table-view-wide {
|
body .table-view-wide {
|
||||||
overflow-x: auto !important;
|
overflow-x: scroll !important;
|
||||||
|
overflow-y: hidden !important;
|
||||||
|
scrollbar-gutter: stable both-edges;
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: rgba(100, 116, 139, 0.5) rgba(226, 232, 240, 0.72);
|
||||||
|
}
|
||||||
|
|
||||||
|
body .table-view-wide::-webkit-scrollbar {
|
||||||
|
height: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body .table-view-wide::-webkit-scrollbar-track {
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(226, 232, 240, 0.72);
|
||||||
|
}
|
||||||
|
|
||||||
|
body .table-view-wide::-webkit-scrollbar-thumb {
|
||||||
|
border: 3px solid rgba(226, 232, 240, 0.72);
|
||||||
|
border-radius: 999px;
|
||||||
|
background: rgba(100, 116, 139, 0.58);
|
||||||
|
}
|
||||||
|
|
||||||
|
body .table-view-wide::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: rgba(71, 85, 105, 0.72);
|
||||||
}
|
}
|
||||||
|
|
||||||
body .table-view-wide .data-table,
|
body .table-view-wide .data-table,
|
||||||
|
|||||||
65
frontend/src/styles/staticCopyAudit.test.js
Normal file
65
frontend/src/styles/staticCopyAudit.test.js
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import assert from "node:assert/strict";
|
||||||
|
import { describe, it } from "node:test";
|
||||||
|
import { readFileSync, readdirSync, statSync } from "node:fs";
|
||||||
|
import { dirname, extname, join } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||||
|
const srcRoot = join(__dirname, "..");
|
||||||
|
|
||||||
|
const bannedVisiblePhrases = [
|
||||||
|
"lite 模式",
|
||||||
|
"当前为内置占位",
|
||||||
|
"真实 LLM",
|
||||||
|
"当前聊天窗口已就绪",
|
||||||
|
"后续在",
|
||||||
|
"占位模式",
|
||||||
|
"系统会自动生成内部默认工艺",
|
||||||
|
"先下载当前仓库类型",
|
||||||
|
"导入会生成期初批次",
|
||||||
|
"每条明细都会写入库存流水",
|
||||||
|
"脑图和组织树共用同一套组织数据",
|
||||||
|
"角色用于配置菜单权限",
|
||||||
|
"为该人员创建或更新系统账号",
|
||||||
|
"新增人员是把基础资料人员挂到当前脑图节点",
|
||||||
|
"用于协助其他用户忘记密码",
|
||||||
|
"系统会自动保存成新版本",
|
||||||
|
"后续小程序报工按",
|
||||||
|
"系统会按退货库",
|
||||||
|
"理论值只是辅助参考",
|
||||||
|
"当前没有可选原材料",
|
||||||
|
"每一条明细都会写入库存流水",
|
||||||
|
"查看影响范围",
|
||||||
|
"点击后系统会锁定当前仓库"
|
||||||
|
];
|
||||||
|
|
||||||
|
function collectSourceFiles(dir) {
|
||||||
|
return readdirSync(dir)
|
||||||
|
.flatMap((entry) => {
|
||||||
|
const fullPath = join(dir, entry);
|
||||||
|
const stat = statSync(fullPath);
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
return collectSourceFiles(fullPath);
|
||||||
|
}
|
||||||
|
if (![".vue", ".js"].includes(extname(fullPath)) || fullPath.endsWith(".test.js")) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
return [fullPath];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("static visible copy audit", () => {
|
||||||
|
it("keeps demo-like always-visible helper copy out of the product UI", () => {
|
||||||
|
const violations = [];
|
||||||
|
for (const filePath of collectSourceFiles(srcRoot)) {
|
||||||
|
const source = readFileSync(filePath, "utf8");
|
||||||
|
for (const phrase of bannedVisiblePhrases) {
|
||||||
|
if (source.includes(phrase)) {
|
||||||
|
violations.push(`${filePath.replace(`${srcRoot}/`, "")}: ${phrase}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.deepEqual(violations, []);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -868,8 +868,8 @@
|
|||||||
<button class="ghost-button" type="button" :disabled="!specialAdjustmentForm.reason.trim()" @click="addSpecialAdjustmentLine">
|
<button class="ghost-button" type="button" :disabled="!specialAdjustmentForm.reason.trim()" @click="addSpecialAdjustmentLine">
|
||||||
添加调整明细
|
添加调整明细
|
||||||
</button>
|
</button>
|
||||||
<span v-if="!specialAdjustmentForm.reason.trim()" class="special-adjustment-tip">请先填写调整说明</span>
|
<span v-if="!specialAdjustmentForm.reason.trim()" class="special-adjustment-tip">填写调整说明后添加明细</span>
|
||||||
<span v-else>每条明细都会写入库存流水,调整说明会同步进入变更记录。</span>
|
<span v-else>可添加调整明细</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="special-adjustment-paper-lines special-adjustment-lines" :class="{ 'is-empty': !specialAdjustmentForm.lines.length }">
|
<div class="special-adjustment-paper-lines special-adjustment-lines" :class="{ 'is-empty': !specialAdjustmentForm.lines.length }">
|
||||||
@ -994,8 +994,7 @@
|
|||||||
</article>
|
</article>
|
||||||
|
|
||||||
<div v-if="!specialAdjustmentForm.lines.length" class="special-adjustment-empty">
|
<div v-if="!specialAdjustmentForm.lines.length" class="special-adjustment-empty">
|
||||||
<strong>还没有调整明细</strong>
|
<strong>暂无调整明细</strong>
|
||||||
<span>先填写调整说明,再点击“添加调整明细”。每一条明细都会写入库存流水。</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -1344,7 +1343,6 @@
|
|||||||
<div class="import-layout">
|
<div class="import-layout">
|
||||||
<section class="import-card">
|
<section class="import-card">
|
||||||
<strong>导出模版</strong>
|
<strong>导出模版</strong>
|
||||||
<p>先下载当前仓库类型的期初导入模版,按实际清点库存填写后再导入。</p>
|
|
||||||
<button class="primary-button" type="button" :disabled="openingImportBusy" @click="exportOpeningTemplate">
|
<button class="primary-button" type="button" :disabled="openingImportBusy" @click="exportOpeningTemplate">
|
||||||
{{ openingImportBusy ? "处理中..." : `导出${activeInventoryLabel}期初模版` }}
|
{{ openingImportBusy ? "处理中..." : `导出${activeInventoryLabel}期初模版` }}
|
||||||
</button>
|
</button>
|
||||||
@ -1355,7 +1353,6 @@
|
|||||||
<input ref="openingImportInputRef" class="hidden-file-input" type="file" accept=".xlsx,.xlsm" @change="importOpeningInventory" />
|
<input ref="openingImportInputRef" class="hidden-file-input" type="file" accept=".xlsx,.xlsm" @change="importOpeningInventory" />
|
||||||
<span class="import-icon">XLSX</span>
|
<span class="import-icon">XLSX</span>
|
||||||
<strong>{{ openingImportBusy ? "导入中..." : "上传期初库存 Excel" }}</strong>
|
<strong>{{ openingImportBusy ? "导入中..." : "上传期初库存 Excel" }}</strong>
|
||||||
<p>导入会生成期初批次、库存余额和库存流水;批次号重复会被拦截。</p>
|
|
||||||
</label>
|
</label>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
@ -1366,7 +1363,6 @@
|
|||||||
:open="productionDrawerOpen"
|
:open="productionDrawerOpen"
|
||||||
eyebrow="原材料库 · 生产出库"
|
eyebrow="原材料库 · 生产出库"
|
||||||
title="生产出库"
|
title="生产出库"
|
||||||
description="选择原材料库存批次出库,后续小程序报工按库存批次号推进。"
|
|
||||||
tag="生产出库"
|
tag="生产出库"
|
||||||
wide
|
wide
|
||||||
@close="productionDrawerOpen = false"
|
@close="productionDrawerOpen = false"
|
||||||
@ -1383,10 +1379,6 @@
|
|||||||
<div v-if="feedbackMessage" class="feedback-banner">{{ feedbackMessage }}</div>
|
<div v-if="feedbackMessage" class="feedback-banner">{{ feedbackMessage }}</div>
|
||||||
<div v-if="errorMessage" class="feedback-banner error-banner">{{ errorMessage }}</div>
|
<div v-if="errorMessage" class="feedback-banner error-banner">{{ errorMessage }}</div>
|
||||||
<WarehouseDocumentSection index="01" title="生产出库信息">
|
<WarehouseDocumentSection index="01" title="生产出库信息">
|
||||||
<div class="document-inline-summary production-out-paper-tip">
|
|
||||||
选择原材料库存批次出库,后续小程序报工按库存批次号推进。一次生产出库只能选择一个材料库存批次。
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="document-control-grid production-out-paper-grid">
|
<div class="document-control-grid production-out-paper-grid">
|
||||||
<label class="document-paper-field document-paper-field-wide">
|
<label class="document-paper-field document-paper-field-wide">
|
||||||
<span>产品</span>
|
<span>产品</span>
|
||||||
@ -1464,10 +1456,6 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="feedback-banner">
|
|
||||||
单件毛重:{{ selectedBomGrossWeight ? formatWeight(selectedBomGrossWeight) : "未配置" }};参考生产数量 = 本次生产出库重量 ÷ 单件毛重。
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="document-control-grid production-out-paper-grid production-out-paper-remark">
|
<div class="document-control-grid production-out-paper-grid production-out-paper-remark">
|
||||||
<label class="document-paper-field document-paper-field-full">
|
<label class="document-paper-field document-paper-field-full">
|
||||||
<span>备注</span>
|
<span>备注</span>
|
||||||
@ -1865,8 +1853,8 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="document-inline-summary return-rework-trace-summary">
|
<div v-if="selectedReturnReworkItem" class="document-inline-summary return-rework-trace-summary">
|
||||||
{{ selectedReturnReworkItem ? formatReturnTraceSummary(selectedReturnReworkItem) : "请选择退货明细,系统会按退货库锁定批次办理返工出库。" }}
|
{{ formatReturnTraceSummary(selectedReturnReworkItem) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="warehouse-paper-control-grid return-rework-paper-grid">
|
<div class="warehouse-paper-control-grid return-rework-paper-grid">
|
||||||
@ -2072,10 +2060,6 @@
|
|||||||
<div v-if="feedbackMessage" class="feedback-banner">{{ feedbackMessage }}</div>
|
<div v-if="feedbackMessage" class="feedback-banner">{{ feedbackMessage }}</div>
|
||||||
<div v-if="errorMessage" class="feedback-banner error-banner">{{ errorMessage }}</div>
|
<div v-if="errorMessage" class="feedback-banner error-banner">{{ errorMessage }}</div>
|
||||||
<WarehouseDocumentSection index="01" title="生产台账入库结算信息">
|
<WarehouseDocumentSection index="01" title="生产台账入库结算信息">
|
||||||
<div class="document-inline-summary production-ledger-inbound-tip">
|
|
||||||
选择生产台账后,系统按领料重量、单件毛重和已入库成品数量填入理论余料、理论废料。理论值只是辅助参考,实际称重可修改;偏差超过上下15%时需要填写说明。
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="document-control-grid production-ledger-inbound-paper-grid">
|
<div class="document-control-grid production-ledger-inbound-paper-grid">
|
||||||
<label class="document-paper-field document-paper-field-wide">
|
<label class="document-paper-field document-paper-field-wide">
|
||||||
<span>生产台账</span>
|
<span>生产台账</span>
|
||||||
@ -2546,7 +2530,7 @@ const operationMatrix = computed(() => ({
|
|||||||
makeOperation("raw-special-in", "in", "SPECIAL_IN", "特殊入库", "强制填写说明后,直接调整原材料库库存明细。", "specialAdjustment")
|
makeOperation("raw-special-in", "in", "SPECIAL_IN", "特殊入库", "强制填写说明后,直接调整原材料库库存明细。", "specialAdjustment")
|
||||||
],
|
],
|
||||||
outbound: [
|
outbound: [
|
||||||
makeOperation("raw-production-out", "out", "PRODUCTION_OUT", "生产出库", "选择原材料库存批次出库,后续小程序报工按库存批次号推进。", "production"),
|
makeOperation("raw-production-out", "out", "PRODUCTION_OUT", "生产出库", "生产出库", "production"),
|
||||||
makeOperation("raw-outsourcing-out", "out", "OUTSOURCING_OUT", "委外出库", "原材料出库给第三方加工。"),
|
makeOperation("raw-outsourcing-out", "out", "OUTSOURCING_OUT", "委外出库", "原材料出库给第三方加工。"),
|
||||||
makeOperation("raw-return-out", "out", "PURCHASE_RETURN_OUT", "退货出库", "入仓后发现质量或性能不合格的原材料退回供应商。", "rawReturn"),
|
makeOperation("raw-return-out", "out", "PURCHASE_RETURN_OUT", "退货出库", "入仓后发现质量或性能不合格的原材料退回供应商。", "rawReturn"),
|
||||||
makeOperation("raw-scrap-out", "out", "SCRAP_OUT", "报废出库", "原材料报废出库。"),
|
makeOperation("raw-scrap-out", "out", "SCRAP_OUT", "报废出库", "原材料报废出库。"),
|
||||||
|
|||||||
@ -36,12 +36,11 @@ describe("ProductSpecLiteView operation foundation loading", () => {
|
|||||||
assert.match(source, /await deleteResource\(`\/master-data\/product-specs\/\$\{createdProductItemId\}`\)\.catch\(\(\) => null\);/);
|
assert.match(source, /await deleteResource\(`\/master-data\/product-specs\/\$\{createdProductItemId\}`\)\.catch\(\(\) => null\);/);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses a one-screen table layout so the action and pagination areas do not get pushed into the edge", () => {
|
it("does not override wide mode with a product-spec-only one-screen table layout", () => {
|
||||||
assert.match(source, /class="table-wrap product-spec-table-wrap"/);
|
assert.doesNotMatch(source, /product-spec-table-wrap/);
|
||||||
assert.match(source, /class="data-table compact-table product-spec-table"/);
|
assert.doesNotMatch(source, /product-spec-table/);
|
||||||
assert.match(source, /<colgroup>[\s\S]*product-spec-col-action[\s\S]*<\/colgroup>/);
|
assert.doesNotMatch(source, /<colgroup>[\s\S]*product-spec-col-action[\s\S]*<\/colgroup>/);
|
||||||
assert.match(source, /\.product-spec-table-wrap\.table-view-wide,[\s\S]*?overflow-x:\s*hidden !important;/);
|
assert.doesNotMatch(source, /overflow-x:\s*hidden !important/);
|
||||||
assert.match(source, /\.product-spec-table[\s\S]*?table-layout:\s*fixed !important;/);
|
assert.doesNotMatch(source, /table-layout:\s*fixed !important;[\s\S]*product-spec/);
|
||||||
assert.match(source, /\.product-spec-table\s+\.action-row[\s\S]*?width:\s*100% !important;/);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -23,25 +23,8 @@
|
|||||||
placeholder="搜索考勤点、产品编码、名称、版本、原材料、小程序工序"
|
placeholder="搜索考勤点、产品编码、名称、版本、原材料、小程序工序"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="table-wrap product-spec-table-wrap">
|
<div class="table-wrap">
|
||||||
<table class="data-table compact-table product-spec-table">
|
<table class="data-table compact-table">
|
||||||
<colgroup>
|
|
||||||
<col class="product-spec-col-code" />
|
|
||||||
<col class="product-spec-col-attendance" />
|
|
||||||
<col class="product-spec-col-project" />
|
|
||||||
<col class="product-spec-col-product" />
|
|
||||||
<col class="product-spec-col-version" />
|
|
||||||
<col class="product-spec-col-weight" />
|
|
||||||
<col class="product-spec-col-material" />
|
|
||||||
<col class="product-spec-col-gross" />
|
|
||||||
<col class="product-spec-col-rate" />
|
|
||||||
<col class="product-spec-col-rate" />
|
|
||||||
<col class="product-spec-col-price" />
|
|
||||||
<col class="product-spec-col-process" />
|
|
||||||
<col class="product-spec-col-beat" />
|
|
||||||
<col class="product-spec-col-status" />
|
|
||||||
<col class="product-spec-col-action" />
|
|
||||||
</colgroup>
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>产品编码</th>
|
<th>产品编码</th>
|
||||||
@ -116,14 +99,13 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<PaginationBar class="product-spec-pagination" v-model:page="page" v-model:page-size="pageSize" :total="filteredRows.length" />
|
<PaginationBar v-model:page="page" v-model:page-size="pageSize" :total="filteredRows.length" />
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<FormDrawer
|
<FormDrawer
|
||||||
:open="drawerOpen"
|
:open="drawerOpen"
|
||||||
eyebrow="产品需规"
|
eyebrow="产品需规"
|
||||||
:title="editingRow ? '编辑产品需规' : '新增产品需规'"
|
:title="editingRow ? '编辑产品需规' : '新增产品需规'"
|
||||||
description="lite 模式下,一个抽屉完成产品资料、默认用料和小程序报工字段。系统会按小程序工序自动生成内部默认工艺,供生产工单使用。"
|
|
||||||
tag="产品需规清单"
|
tag="产品需规清单"
|
||||||
wide
|
wide
|
||||||
@close="drawerOpen = false"
|
@close="drawerOpen = false"
|
||||||
@ -1088,177 +1070,6 @@ onActivated(async () => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
.product-spec-table-wrap,
|
|
||||||
.product-spec-table-wrap.table-view-wide,
|
|
||||||
.product-spec-table-wrap.table-view-overview {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
overflow-x: hidden !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-table,
|
|
||||||
.product-spec-table.data-table-wide,
|
|
||||||
.product-spec-table.data-table-overview,
|
|
||||||
.product-spec-table-wrap.table-view-wide .product-spec-table,
|
|
||||||
.product-spec-table-wrap.table-view-overview .product-spec-table {
|
|
||||||
width: 100% !important;
|
|
||||||
min-width: 100% !important;
|
|
||||||
max-width: 100% !important;
|
|
||||||
table-layout: fixed !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-col-code {
|
|
||||||
width: 8%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-col-attendance {
|
|
||||||
width: 5.5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-col-project {
|
|
||||||
width: 8.5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-col-product {
|
|
||||||
width: 10.5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-col-version {
|
|
||||||
width: 4.2%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-col-weight {
|
|
||||||
width: 4.6%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-col-material {
|
|
||||||
width: 11%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-col-gross {
|
|
||||||
width: 5.4%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-col-rate {
|
|
||||||
width: 5.7%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-col-price {
|
|
||||||
width: 5.4%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-col-process {
|
|
||||||
width: 6.2%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-col-beat {
|
|
||||||
width: 5.2%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-col-status {
|
|
||||||
width: 5%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-col-action {
|
|
||||||
width: 8.6%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-table th,
|
|
||||||
.product-spec-table td,
|
|
||||||
.product-spec-table.data-table-wide th,
|
|
||||||
.product-spec-table.data-table-overview th,
|
|
||||||
.product-spec-table-wrap.table-view-wide .product-spec-table th,
|
|
||||||
.product-spec-table-wrap.table-view-overview .product-spec-table th {
|
|
||||||
min-width: 0 !important;
|
|
||||||
max-width: 100% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-table th,
|
|
||||||
.product-spec-table th :deep(.sortable-th-button),
|
|
||||||
.product-spec-table th :deep(.sortable-th-label) {
|
|
||||||
overflow: visible !important;
|
|
||||||
text-overflow: clip !important;
|
|
||||||
white-space: normal !important;
|
|
||||||
word-break: keep-all !important;
|
|
||||||
overflow-wrap: anywhere !important;
|
|
||||||
line-height: 1.22;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-table th :deep(.sortable-th-button) {
|
|
||||||
grid-template-columns: minmax(0, 1fr) 16px !important;
|
|
||||||
column-gap: 4px !important;
|
|
||||||
min-width: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-table th :deep(.sortable-th-label) {
|
|
||||||
min-width: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-table td:not(.action-row),
|
|
||||||
.product-spec-table.data-table-wide td:not(.action-row),
|
|
||||||
.product-spec-table.data-table-overview td:not(.action-row) {
|
|
||||||
min-width: 0 !important;
|
|
||||||
max-width: 100% !important;
|
|
||||||
overflow: hidden !important;
|
|
||||||
text-overflow: ellipsis !important;
|
|
||||||
white-space: nowrap !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-table .action-row,
|
|
||||||
.product-spec-table.data-table-wide .action-row,
|
|
||||||
.product-spec-table.data-table-overview .action-row {
|
|
||||||
width: 100% !important;
|
|
||||||
min-width: 0 !important;
|
|
||||||
max-width: 100% !important;
|
|
||||||
padding-right: 8px !important;
|
|
||||||
padding-left: 8px !important;
|
|
||||||
text-align: center !important;
|
|
||||||
white-space: nowrap !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-table-wrap.table-view-wide .product-spec-table:has(td.action-row) thead th:last-child,
|
|
||||||
.product-spec-table-wrap.table-view-overview .product-spec-table:has(td.action-row) thead th:last-child,
|
|
||||||
.product-spec-table.data-table-wide:has(td.action-row) thead th:last-child,
|
|
||||||
.product-spec-table.data-table-overview:has(td.action-row) thead th:last-child {
|
|
||||||
width: auto !important;
|
|
||||||
min-width: 0 !important;
|
|
||||||
max-width: 100% !important;
|
|
||||||
text-align: center !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-table .action-row .ghost-button,
|
|
||||||
.product-spec-table .action-row :deep(.semantic-action-button) {
|
|
||||||
width: calc((100% - 6px) / 2) !important;
|
|
||||||
min-width: 0 !important;
|
|
||||||
max-width: none !important;
|
|
||||||
justify-content: center !important;
|
|
||||||
margin-right: 0 !important;
|
|
||||||
padding: 0 6px !important;
|
|
||||||
gap: 5px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-table .action-row .ghost-button + .ghost-button,
|
|
||||||
.product-spec-table .action-row :deep(.semantic-action-button + .semantic-action-button) {
|
|
||||||
margin-left: 6px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-table .action-row :deep(.semantic-action-label) {
|
|
||||||
min-width: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-pagination {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.product-spec-pagination :deep(.pagination-actions) {
|
|
||||||
min-width: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.process-field-list {
|
.process-field-list {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
|
|||||||
@ -34,7 +34,7 @@ describe("SystemExtensionView workbench redesign", () => {
|
|||||||
assert.doesNotMatch(source, /<small>{{ section\.desc }}<\/small>/);
|
assert.doesNotMatch(source, /<small>{{ section\.desc }}<\/small>/);
|
||||||
assert.doesNotMatch(source, /activeSectionMeta\.eyebrow/);
|
assert.doesNotMatch(source, /activeSectionMeta\.eyebrow/);
|
||||||
assert.doesNotMatch(source, /extension-impact-list/);
|
assert.doesNotMatch(source, /extension-impact-list/);
|
||||||
assert.match(source, /extension-detail-note/);
|
assert.doesNotMatch(source, /extension-detail-note/);
|
||||||
assert.match(source, /extension-preview-disclosure/);
|
assert.match(source, /extension-preview-disclosure/);
|
||||||
assert.match(source, /extension-field-grid/);
|
assert.match(source, /extension-field-grid/);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -149,11 +149,6 @@
|
|||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
|
|
||||||
<details class="extension-detail-note">
|
|
||||||
<summary>查看影响范围</summary>
|
|
||||||
<p>开启时显示工序报工和小程序证据;关闭时隐藏工序报工,生产按 ERP 入库闭环推进。</p>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<label class="form-field">
|
<label class="form-field">
|
||||||
<span>说明</span>
|
<span>说明</span>
|
||||||
<input v-model.trim="smartOperationReportForm.remark" type="text" placeholder="例如:客户未购买小程序模块,暂按ERP入库反推" />
|
<input v-model.trim="smartOperationReportForm.remark" type="text" placeholder="例如:客户未购买小程序模块,暂按ERP入库反推" />
|
||||||
@ -201,7 +196,7 @@
|
|||||||
<input v-model="assistantForm.enabled" type="checkbox" />
|
<input v-model="assistantForm.enabled" type="checkbox" />
|
||||||
<span class="switch-track" aria-hidden="true"></span>
|
<span class="switch-track" aria-hidden="true"></span>
|
||||||
<span>
|
<span>
|
||||||
<strong>启用真实 LLM 调用</strong>
|
<strong>启用智能助手</strong>
|
||||||
<small class="extension-inline-state">{{ assistantConfig.api_key_configured ? "密钥已配置" : "未配置密钥" }}</small>
|
<small class="extension-inline-state">{{ assistantConfig.api_key_configured ? "密钥已配置" : "未配置密钥" }}</small>
|
||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
@ -625,7 +620,7 @@ const assistantStateLabel = computed(() => {
|
|||||||
if (assistantConfig.value.api_key_configured) {
|
if (assistantConfig.value.api_key_configured) {
|
||||||
return "密钥已配置";
|
return "密钥已配置";
|
||||||
}
|
}
|
||||||
return "占位模式";
|
return "未启用";
|
||||||
});
|
});
|
||||||
|
|
||||||
const statusCards = computed(() => [
|
const statusCards = computed(() => [
|
||||||
|
|||||||
@ -39,7 +39,6 @@
|
|||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">组织架构</p>
|
<p class="eyebrow">组织架构</p>
|
||||||
<h3>权限组织架构</h3>
|
<h3>权限组织架构</h3>
|
||||||
<p class="permission-note">脑图和组织树共用同一套组织数据;脑图模式下员工节点默认收拢,人员授权和移除都在组织架构里处理。</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mindmap-card-actions">
|
<div class="mindmap-card-actions">
|
||||||
<div class="org-view-switch" role="tablist" aria-label="组织架构展示模式">
|
<div class="org-view-switch" role="tablist" aria-label="组织架构展示模式">
|
||||||
@ -95,7 +94,6 @@
|
|||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">角色权限</p>
|
<p class="eyebrow">角色权限</p>
|
||||||
<h3>角色维护</h3>
|
<h3>角色维护</h3>
|
||||||
<p class="permission-note">角色用于配置菜单权限和业务身份;人员授权请回到组织架构中对人员节点操作。</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="row-actions">
|
<div class="row-actions">
|
||||||
<button
|
<button
|
||||||
@ -161,7 +159,6 @@
|
|||||||
<div>
|
<div>
|
||||||
<p class="eyebrow">人员授权</p>
|
<p class="eyebrow">人员授权</p>
|
||||||
<h2>{{ authorizingEmployee?.employee_name || "人员授权" }}</h2>
|
<h2>{{ authorizingEmployee?.employee_name || "人员授权" }}</h2>
|
||||||
<p class="authorize-header-note">为该人员创建或更新系统账号,并分配可访问的系统角色。</p>
|
|
||||||
</div>
|
</div>
|
||||||
<button class="ghost-button authorize-close-button" type="button" @click="showAuthorizeDrawer = false">关闭窗口</button>
|
<button class="ghost-button authorize-close-button" type="button" @click="showAuthorizeDrawer = false">关闭窗口</button>
|
||||||
</div>
|
</div>
|
||||||
@ -329,9 +326,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="orgDrawerMode === 'create' || orgDrawerMode === 'rename'">
|
<div v-if="orgDrawerMode === 'create' || orgDrawerMode === 'rename'">
|
||||||
<p v-if="orgDrawerMode === 'create'" class="permission-note">
|
|
||||||
将在「{{ orgForm.parent_label }}」下新增{{ nodeTypeLabel(orgForm.node_type) }},只需要填写名称。
|
|
||||||
</p>
|
|
||||||
<label class="form-field">
|
<label class="form-field">
|
||||||
<span>{{ nodeTypeLabel(orgForm.node_type) }}名称</span>
|
<span>{{ nodeTypeLabel(orgForm.node_type) }}名称</span>
|
||||||
<input v-model="orgForm.node_label" type="text" placeholder="请输入名称" />
|
<input v-model="orgForm.node_label" type="text" placeholder="请输入名称" />
|
||||||
@ -339,7 +333,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="orgDrawerMode === 'manager'">
|
<div v-else-if="orgDrawerMode === 'manager'">
|
||||||
<p class="permission-note">支持绑定多位主管,直接点击人员卡片即可选中或取消,不需要按键盘组合键。</p>
|
|
||||||
<div class="form-field">
|
<div class="form-field">
|
||||||
<span>多位主管</span>
|
<span>多位主管</span>
|
||||||
<div class="selected-manager-tags">
|
<div class="selected-manager-tags">
|
||||||
@ -381,7 +374,6 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="orgDrawerMode === 'employee'">
|
<div v-else-if="orgDrawerMode === 'employee'">
|
||||||
<p class="permission-note">新增人员是把基础资料人员挂到当前脑图节点,不会修改小程序人员主数据。</p>
|
|
||||||
<label class="form-field">
|
<label class="form-field">
|
||||||
<span>人员</span>
|
<span>人员</span>
|
||||||
<select v-model="orgEmployeeForm.employee_id">
|
<select v-model="orgEmployeeForm.employee_id">
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user