面向 Cursor / AI 编程助手执行。每次只做一个 Batch,完成验收后再继续下一个。
<script setup lang="ts"> + Admin.NET service 实例,禁用 S0 的 http.js 和 useCrudPage.js。Startup.cs、SysMenuSeedData.cs、aidopMenuDisplay.ts,追加内容,不替换已有内容。| 维度 | S0 独立项目 | → AiDOPWarehouse 目标位置 |
|---|---|---|
| 实体 | S0.Domain.*.XxxEntity (EF Core BaseEntity) |
server/Plugins/Admin.NET.Plugin.AiDOP/Entity/S0/[模块]/AdoS0Xxx.cs |
| DTO | S0.Application.*.XxxDto / XxxRequest |
server/Plugins/Admin.NET.Plugin.AiDOP/Dto/S0/[模块]/AdoS0XxxDtos.cs |
| 控制器 | S0.Api.Controllers.*.*Controller (EF Core Service) |
server/Plugins/Admin.NET.Plugin.AiDOP/Controllers/S0/[模块]/AdoS0XxxController.cs |
| 表名 | plat_company 等 |
ado_s0_platform_company 等(加 ado_s0_ 前缀) |
| 前端 API | src/api/modules/xxx.js (S0 http.js) |
Web/src/views/aidop/s0/api/s0XxxApi.ts |
| 前端页面 | src/views/xxx/XxxList.vue (JS) |
Web/src/views/aidop/s0/[模块]/XxxList.vue (TS) |
实体类名 : AdoS0<PascalName> 示例: AdoS0Company
表名 : ado_s0_<module>_<name> 示例: ado_s0_platform_company
控制器路由 : api/s0/<module>/<name> 示例: api/s0/platform/companies
命名空间 : Admin.NET.Plugin.AiDOP.Entity.S0.<Module>
: Admin.NET.Plugin.AiDOP.Dto.S0.<Module>
: Admin.NET.Plugin.AiDOP.Controllers.S0.<Module>
namespace Admin.NET.Plugin.AiDOP.Entity.S0.Platform;
/// <summary>公司主数据(S0 Platform / plat_company)</summary>
[SugarTable("ado_s0_platform_company", "S0 公司主数据")]
public class AdoS0Company
{
[SugarColumn(ColumnDescription = "主键", IsPrimaryKey = true, IsIdentity = true, ColumnDataType = "bigint")]
public long Id { get; set; }
[SugarColumn(ColumnDescription = "公司编码", Length = 50)]
public string Code { get; set; } = string.Empty;
[SugarColumn(ColumnDescription = "公司名称", Length = 200)]
public string Name { get; set; } = string.Empty;
[SugarColumn(ColumnDescription = "简称", Length = 100, IsNullable = true)]
public string? ShortName { get; set; }
[SugarColumn(ColumnDescription = "地址", Length = 500, IsNullable = true)]
public string? Address { get; set; }
[SugarColumn(ColumnDescription = "备注", Length = 500, IsNullable = true)]
public string? Remark { get; set; }
[SugarColumn(ColumnDescription = "启用", ColumnDataType = "boolean")]
public bool IsEnabled { get; set; } = true;
[SugarColumn(ColumnDescription = "创建时间")]
public DateTime CreatedAt { get; set; } = DateTime.Now;
[SugarColumn(ColumnDescription = "更新时间", IsNullable = true)]
public DateTime? UpdatedAt { get; set; }
}
注意:
- 不继承任何基类(S0 的
BaseEntity字段逐一内联为[SugarColumn]列)。- S0 中的导航属性(如
public Company? Company { get; set; })不迁移。IsDeleted软删除字段不迁移(后端直接物理删除,前端通过空列表反映结果)。VersionNo并发版本字段不迁移(插件层不做并发冲突处理)。CompanyRefId/FactoryRefId等关联 ID 以long外键字段保留,命名保持与 S0 一致。
using Admin.NET.Plugin.AiDOP.Dto.S0.Platform;
using Admin.NET.Plugin.AiDOP.Entity.S0.Platform;
namespace Admin.NET.Plugin.AiDOP.Controllers.S0.Platform;
/// <summary>S0 公司主数据</summary>
[ApiController]
[Route("api/s0/platform/companies")]
[AllowAnonymous]
[NonUnify]
public class AdoS0CompaniesController : ControllerBase
{
private readonly SqlSugarRepository<AdoS0Company> _rep;
public AdoS0CompaniesController(SqlSugarRepository<AdoS0Company> rep) => _rep = rep;
[HttpGet]
public async Task<IActionResult> GetPagedAsync([FromQuery] AdoS0CompanyQueryDto q)
{
var total = 0;
var list = await _rep.AsQueryable()
.WhereIF(!string.IsNullOrWhiteSpace(q.Code), x => x.Code.Contains(q.Code!))
.WhereIF(!string.IsNullOrWhiteSpace(q.Name), x => x.Name.Contains(q.Name!))
.WhereIF(q.IsEnabled.HasValue, x => x.IsEnabled == q.IsEnabled!.Value)
.ToPageListAsync(q.Page, q.PageSize, ref total);
return Ok(new { total, page = q.Page, pageSize = q.PageSize, list });
}
[HttpGet("{id:long}")]
public async Task<IActionResult> GetAsync(long id)
{
var item = await _rep.GetByIdAsync(id);
return item is null ? NotFound() : Ok(item);
}
[HttpPost]
public async Task<IActionResult> CreateAsync([FromBody] AdoS0CompanyUpsertDto dto)
{
var entity = new AdoS0Company
{
Code = dto.Code,
Name = dto.Name,
ShortName = dto.ShortName,
Address = dto.Address,
Remark = dto.Remark,
IsEnabled = dto.IsEnabled,
CreatedAt = DateTime.Now
};
await _rep.InsertAsync(entity);
return Ok(entity);
}
[HttpPut("{id:long}")]
public async Task<IActionResult> UpdateAsync(long id, [FromBody] AdoS0CompanyUpsertDto dto)
{
var entity = await _rep.GetByIdAsync(id);
if (entity is null) return NotFound();
entity.Code = dto.Code;
entity.Name = dto.Name;
entity.ShortName = dto.ShortName;
entity.Address = dto.Address;
entity.Remark = dto.Remark;
entity.IsEnabled = dto.IsEnabled;
entity.UpdatedAt = DateTime.Now;
await _rep.UpdateAsync(entity);
return Ok(entity);
}
[HttpDelete("{id:long}")]
public async Task<IActionResult> DeleteAsync(long id)
{
await _rep.DeleteByIdAsync(id);
return Ok();
}
}
namespace Admin.NET.Plugin.AiDOP.Dto.S0.Platform;
public class AdoS0CompanyQueryDto
{
public string? Code { get; set; }
public string? Name { get; set; }
public bool? IsEnabled { get; set; }
public int Page { get; set; } = 1;
public int PageSize { get; set; } = 20;
}
public class AdoS0CompanyUpsertDto
{
public string Code { get; set; } = string.Empty;
public string Name { get; set; } = string.Empty;
public string? ShortName { get; set; }
public string? Address { get; set; }
public string? Remark { get; set; }
public bool IsEnabled { get; set; } = true;
}
// Web/src/views/aidop/s0/api/s0PlatformApi.ts
import service from '/@/utils/request';
function unwrap<T>(res: { data: T }): T { return res.data; }
export interface Paged<T> { total: number; page: number; pageSize: number; list: T[]; }
export interface S0CompanyRow {
id: number; code: string; name: string;
shortName?: string | null; address?: string | null;
remark?: string | null; isEnabled: boolean;
createdAt?: string; updatedAt?: string | null;
}
export interface S0CompanyUpsert {
code: string; name: string;
shortName?: string; address?: string;
remark?: string; isEnabled: boolean;
}
export const s0CompaniesApi = {
list: (params: Record<string, unknown>) =>
service.get<Paged<S0CompanyRow>>('/api/s0/platform/companies', { params }).then(unwrap),
get: (id: number) =>
service.get<S0CompanyRow>(`/api/s0/platform/companies/${id}`).then(unwrap),
create: (body: S0CompanyUpsert) =>
service.post<S0CompanyRow>('/api/s0/platform/companies', body).then(unwrap),
update: (id: number, body: S0CompanyUpsert) =>
service.put<S0CompanyRow>(`/api/s0/platform/companies/${id}`, body).then(unwrap),
delete: (id: number) =>
service.delete(`/api/s0/platform/companies/${id}`).then(unwrap),
};
<!-- Web/src/views/aidop/s0/platform/CompanyManagement.vue -->
<template>
<AidopDemoShell :title="pageTitle" subtitle="S0 / Platform / 公司主数据">
<!-- 查询栏 -->
<el-form :inline="true" :model="query" class="mb12" @submit.prevent>
<el-form-item label="编码">
<el-input v-model="query.code" clearable style="width:140px" />
</el-form-item>
<el-form-item label="名称">
<el-input v-model="query.name" clearable style="width:160px" />
</el-form-item>
<el-form-item>
<el-button type="primary" @click="loadList">查询</el-button>
<el-button @click="resetQuery">重置</el-button>
<el-button type="success" @click="openCreate">新增</el-button>
</el-form-item>
</el-form>
<!-- 表格 -->
<el-table :data="rows" v-loading="loading" border stripe style="width:100%">
<el-table-column prop="code" label="编码" width="120" />
<el-table-column prop="name" label="名称" min-width="160" />
<el-table-column prop="shortName" label="简称" width="120" />
<el-table-column prop="isEnabled" label="启用" width="80" align="center">
<template #default="{ row }">
<el-tag :type="row.isEnabled ? 'success' : 'info'" size="small">
{{ row.isEnabled ? '是' : '否' }}
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="160" fixed="right" align="center">
<template #default="{ row }">
<el-button link type="primary" @click="openEdit(row)">编辑</el-button>
<el-button link type="danger" @click="onDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<div class="pager">
<el-pagination
v-model:current-page="query.page"
v-model:page-size="query.pageSize"
:total="total"
:page-sizes="[20, 50, 100]"
layout="total, sizes, prev, pager, next"
@current-change="loadList"
@size-change="loadList"
/>
</div>
<!-- 弹窗 -->
<el-dialog
v-model="dialogVisible"
:title="editingId ? '编辑公司' : '新增公司'"
width="480px"
destroy-on-close
>
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px">
<el-form-item label="编码" prop="code">
<el-input v-model="form.code" />
</el-form-item>
<el-form-item label="名称" prop="name">
<el-input v-model="form.name" />
</el-form-item>
<el-form-item label="简称">
<el-input v-model="form.shortName" />
</el-form-item>
<el-form-item label="地址">
<el-input v-model="form.address" />
</el-form-item>
<el-form-item label="启用">
<el-switch v-model="form.isEnabled" />
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" :loading="saving" @click="submitForm">保存</el-button>
</template>
</el-dialog>
</AidopDemoShell>
</template>
<script setup lang="ts" name="aidopS0PlatformCompany">
import { reactive, ref, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { ElMessage, ElMessageBox, type FormInstance, type FormRules } from 'element-plus';
import AidopDemoShell from '../../components/AidopDemoShell.vue';
import { s0CompaniesApi, type S0CompanyRow, type S0CompanyUpsert } from '../api/s0PlatformApi';
const route = useRoute();
const pageTitle = (route.meta?.title as string) || '公司管理';
const rows = ref<S0CompanyRow[]>([]);
const total = ref(0);
const loading = ref(false);
const query = reactive({ code: '', name: '', page: 1, pageSize: 20 });
const dialogVisible = ref(false);
const saving = ref(false);
const editingId = ref<number | null>(null);
const formRef = ref<FormInstance>();
const form = reactive<S0CompanyUpsert>({ code: '', name: '', shortName: '', address: '', isEnabled: true });
const rules: FormRules = {
code: [{ required: true, message: '请填写编码', trigger: 'blur' }],
name: [{ required: true, message: '请填写名称', trigger: 'blur' }],
};
async function loadList() {
loading.value = true;
try {
const r = await s0CompaniesApi.list({ ...query });
rows.value = r.list;
total.value = r.total;
} finally {
loading.value = false;
}
}
function resetQuery() {
Object.assign(query, { code: '', name: '', page: 1 });
loadList();
}
function openCreate() {
editingId.value = null;
Object.assign(form, { code: '', name: '', shortName: '', address: '', isEnabled: true });
dialogVisible.value = true;
}
function openEdit(row: S0CompanyRow) {
editingId.value = row.id;
Object.assign(form, { code: row.code, name: row.name, shortName: row.shortName ?? '', address: row.address ?? '', isEnabled: row.isEnabled });
dialogVisible.value = true;
}
async function submitForm() {
await formRef.value?.validate();
saving.value = true;
try {
if (editingId.value) {
await s0CompaniesApi.update(editingId.value, { ...form });
} else {
await s0CompaniesApi.create({ ...form });
}
ElMessage.success('保存成功');
dialogVisible.value = false;
await loadList();
} finally {
saving.value = false;
}
}
function onDelete(row: S0CompanyRow) {
ElMessageBox.confirm(`确定删除「${row.name}」?`, '确认', { type: 'warning' })
.then(async () => {
await s0CompaniesApi.delete(row.id);
ElMessage.success('已删除');
await loadList();
});
}
onMounted(loadList);
</script>
Id = 1321000001000L(由 ModuleDefinitions 第 1 项自动生成:1321000000000 + 1*1000),Pid = AidopRootId,Name = "aidopDirS0"1329_001_000_000L ~ 1329_099_000_000L(步长 1000)1329_001_000_001L ~ 1329_099_000_999L每批追加菜单时,在
SysMenuSeedData.cs中HasData()末尾foreach之后,新增一个私有方法BuildS0XxxMenus()并在HasData的foreach后用foreach (var m in BuildS0XxxMenus(ct)) list.Add(m);拼入。
每批新增实体后,在 Startup.cs 的 db.CodeFirst.InitTables(...) 调用中追加新实体类型:
// 现有
db.CodeFirst.InitTables(typeof(AdoOrder), typeof(AdoPlan), typeof(AdoWorkOrder));
// Batch 1 后改为:
db.CodeFirst.InitTables(
typeof(AdoOrder), typeof(AdoPlan), typeof(AdoWorkOrder),
// S0 Platform
typeof(AdoS0Company), typeof(AdoS0Factory),
typeof(AdoS0DictType), typeof(AdoS0DictItem)
);
| Batch | 模块 | S0 源目录 | 实体数 | 页面数 | 菜单子目录 ID |
|---|---|---|---|---|---|
| 1 | Platform 基础平台(复用平台) | Domain/Platform |
0(复用 SysOrg + SysDictType/Data) | 0(复用已有页面) | 无需新建 |
| 2 | Sales 产销建模 | Domain/Sales、api/modules/sales.js、views/CustomerManagement.vue 等 |
3 | 3 | 1329002000000L |
| 3 | Manufacturing 制造建模 | Domain/Manufacturing、api/modules/manufacturing.js、views/manufacturing/ |
12 | 18 | 1329003000000L |
| 4 | Warehouse 仓储建模 | Domain/Warehouse、api/modules/warehouse.js、views/warehouse/ |
12 | 12 | 1329004000000L |
| 5 | Quality 质量建模 | Domain/Quality、api/modules/quality.js、views/quality/ |
16 | 16 | 1329005000000L |
| 6 | Supply 供应建模 | Domain/Supply、api/modules/supply.js、views/supply/ |
4 | 3 | 1329006000000L |
| 7 | Business 业务流程 | Domain/Business、api/modules/business.js、views/business/ |
4 | 2 | 1329007000000L |
方案变更:S0 的 Platform 模块(Company / Factory / DictType / DictItem)与 Admin.NET 已有的
SysOrg(组织机构)和SysDictType+SysDictData(字典)高度同构,不再新建独立实体/页面, 改为复用平台表 + 灌入业务种子数据。
| S0 Platform 实体 | 本质 | 目标平台表 | 复用策略 |
|---|---|---|---|
plat_company (Code/Name/ShortName/Address) |
公司主数据 | SysOrg (Type="201"=公司) |
通过"系统管理 > 机构管理"维护,或 SeedData 灌入 |
plat_factory (Code/Name/CompanyRefId) |
工厂主数据 | SysOrg (Type="501"=组,Pid=公司节点) |
同上,用 Pid 父子关系表达归属 |
plat_dict_type (TypeCode/TypeName) |
字典分类 | SysDictType (Code/Name) |
通过"系统管理 > 字典管理"维护,或 SeedData 灌入 |
plat_dict_item (TypeCode/ItemCode/ItemName/SortNo) |
字典值 | SysDictData (DictTypeId/Value/Label/OrderNo) |
同上 |
S0 的 Company → Factory 父子关系映射到 SysOrg 树:
系统默认(集团 Type=101, Id=SqlSugarConst.DefaultTenantId)
├─ 公司A(公司 Type=201, Code="C001", Name="XX有限公司") ← S0 Company
│ ├─ 工厂A1(组 Type=501, Code="F001", Name="一工厂") ← S0 Factory
│ └─ 工厂A2(组 Type=501, Code="F002", Name="二工厂")
└─ 公司B(公司 Type=201, Code="C002")
└─ 工厂B1
SysOrg.Remark可存放 S0 Company 的 Address 信息。SpareText1~3 在 S0 中未实际使用,不迁移。
在 AiDOP 插件中新增种子文件 server/Plugins/Admin.NET.Plugin.AiDOP/SeedData/S0DictSeedData.cs,
向 SysDictType + SysDictData 灌入 S0 各模块所需的业务字典(编码加 s0_ 前缀避免与系统字典冲突):
| 字典 Code | 字典名称 | 值示例 | 消费方 |
|---|---|---|---|
s0_material_type |
物料类型 | raw/semi/finished/aux/fixture/packaging | Batch 2 物料管理 |
s0_pl_category |
计划类别 | purchase/manufacture/outsource | Batch 2 物料管理 |
s0_stock_type |
库存类型 | normal/inspection/consigned/safety | Batch 2 物料管理 |
s0_special_req_type |
特殊需求类型 | common/urgent/export/custom | Batch 2 物料管理 |
s0_material_attribute |
物料属性 | standard/purchase/manufacture/outsource | Batch 2 物料管理 |
s0_customer_type |
客户类型 | domestic/overseas/dealer | Batch 2 客户管理 |
s0_currency |
币种 | CNY/USD/EUR/JPY/HKD | Batch 2 客户管理 |
s0_forbid_status |
禁用状态 | normal/forbidden | 通用 |
后续 Batch 3~7 的字典也在此文件统一追加。
新建文件(1 个):
server/Plugins/Admin.NET.Plugin.AiDOP/SeedData/S0DictSeedData.cs
不新建实体、不新建控制器、不修改 Startup.cs(SysDictType/SysDictData/SysOrg 已由框架 CodeFirst 管理)。
无新建页面。使用已有页面:
views/system/org/index.vue)views/system/dict/index.vue)产销建模等页面中的下拉选择器调用平台标准 API:
// 获取公司列表(Type=201 为公司节点)
import { SysOrgApi } from '/@/api-services/apis/sys-org-api';
// 调用后在前端按 Type 过滤,或后端提供按 Type 过滤的接口
// 获取字典值列表(按字典编码)
import { SysDictDataApi } from '/@/api-services/apis/sys-dict-data-api';
SysDictDataApi.apiSysDictDataDataListCodeGet('s0_material_type')
S0DictSeedData.cs 编译通过sys_dict_type 中可见 s0_* 前缀的字典类型sys_dict_data 中可见对应字典值详细方案见 Batch2-产销建模迁移方案.md
源文件参考路径(只读):
/home/yy968/work/s0/s0-operating-modeling/backend/src/
S0.Domain/Sales/Customer.cs ← [Table("sales_customer")]
S0.Domain/Sales/Material.cs ← [Table("sales_material")](30+ 字段)
S0.Domain/Sales/OrderPriorityRule.cs ← [Table("sales_order_priority_rule")]
S0.Api/Controllers/Sales/CustomersController.cs
S0.Api/Controllers/Sales/MaterialsController.cs
S0.Api/Controllers/Sales/OrderPriorityRulesController.cs
/home/yy968/work/s0/s0-operating-modeling/src/
api/modules/sales.js
views/CustomerManagement.vue ← 路由 /sales-modeling/customers
views/MaterialManagement.vue ← 路由 /sales-modeling/materials
views/OrderPriorityConfig.vue ← 路由 /sales-modeling/order-priority
修正说明:S0.Domain.Sales 实际只有 3 个实体(Customer / Material / OrderPriorityRule), 不含 BOM(原计划误列)。Material 实际含 30+ 字段(库存、采购、质量、批次管理等参数), 远超原计划列出的 10 个字段。
后端 — 新建文件:
Entity/S0/Sales/
AdoS0Customer.cs ← sales_customer → ado_s0_sales_customer(20 字段)
AdoS0Material.cs ← sales_material → ado_s0_sales_material(43 字段)
AdoS0OrderPriorityRule.cs ← sales_order_priority_rule → ado_s0_sales_order_priority_rule(19 字段)
Dto/S0/Sales/
AdoS0SalesDtos.cs ← 3 组 QueryDto + UpsertDto
Controllers/S0/Sales/
AdoS0CustomersController.cs
AdoS0MaterialsController.cs
AdoS0OrderPriorityRulesController.cs
前端 — 新建文件:
Web/src/views/aidop/s0/
api/s0SalesApi.ts
sales/
CustomerList.vue ← name="aidopS0SalesCustomer"
MaterialList.vue ← name="aidopS0SalesMaterial"(el-tabs 分 6 组表单)
OrderPriorityRuleList.vue ← name="aidopS0SalesOrderPriorityRule"
下拉数据源(来自 Batch 1 灌入的平台数据):
SysOrgApi(按 Type 过滤公司/工厂)SysDictDataApi.apiSysDictDataDataListCodeGet('s0_material_type') 等菜单 SeedData 追加(方法名 BuildS0SalesMenus,S0DirId = 1321000001000L,SubDirId = 1329002000000L)
Batch 2 验收标准:
ado_s0_sales_customer、ado_s0_sales_material、ado_s0_sales_order_priority_rule)/api/s0/sales/* 共 15 个接口源文件参考路径(只读):
/home/yy968/work/s0/s0-operating-modeling/backend/src/
S0.Api/Controllers/Manufacturing/ManufacturingControllers.cs ← 多个 Controller 合并在一文件
S0.Application/Manufacturing/
/home/yy968/work/s0/s0-operating-modeling/src/
api/modules/manufacturing.js
views/manufacturing/
RoutingList.vue
ProductionLineList.vue
StandardProcessList.vue
StandardBomManagement.vue
WorkOrderControlParams.vue
MaterialSubstitutionList.vue
PersonnelSkillList.vue
PersonSkillAssignmentList.vue
LineMaterialList.vue
LinePostList.vue
WorkCenterList.vue
MaterialProcessElementList.vue
ProductionElementParamList.vue
PreprocessElementList.vue
PreprocessElementParamList.vue
SopFileTypeList.vue
SopMaintenanceList.vue
ManufacturingCrudPage.vue ← 含多个子路由入口
ManufacturingAggregatePage.vue
ManufacturingTodoPage.vue
后端 — 新建实体(约 12 个):
Entity/S0/Manufacturing/
AdoS0StandardOperation.cs → ado_s0_mfg_standard_operation
AdoS0ProductionLine.cs → ado_s0_mfg_production_line
AdoS0Routing.cs → ado_s0_mfg_routing
AdoS0RoutingOperation.cs → ado_s0_mfg_routing_operation
AdoS0MaterialSubstitution.cs → ado_s0_mfg_material_substitution
AdoS0WorkOrderControl.cs → ado_s0_mfg_work_order_control
AdoS0PersonSkill.cs → ado_s0_mfg_person_skill
AdoS0WorkCenter.cs → ado_s0_mfg_work_center
AdoS0LineMaterial.cs → ado_s0_mfg_line_material
AdoS0LinePost.cs → ado_s0_mfg_line_post
AdoS0SopFileType.cs → ado_s0_mfg_sop_file_type
AdoS0MaterialProcessElement.cs → ado_s0_mfg_material_process_element
实体字段:从
ManufacturingControllers.cs和AppDbContext.cs的ConfigureManufacturing段读取全部字段定义,逐一转为[SugarColumn]格式。
前端 — 新建文件:
Web/src/views/aidop/s0/
api/s0ManufacturingApi.ts
manufacturing/
RoutingList.vue ← name="aidopS0MfgRouting"
ProductionLineList.vue ← name="aidopS0MfgProductionLine"
StandardProcessList.vue ← name="aidopS0MfgStandardProcess"
WorkOrderControlParams.vue ← name="aidopS0MfgWorkOrderControl"
MaterialSubstitutionList.vue ← name="aidopS0MfgMaterialSubstitution"
PersonnelSkillList.vue ← name="aidopS0MfgPersonSkill"
WorkCenterList.vue ← name="aidopS0MfgWorkCenter"
LineMaterialList.vue ← name="aidopS0MfgLineMaterial"
LinePostList.vue ← name="aidopS0MfgLinePost"
SopFileTypeList.vue ← name="aidopS0MfgSopFileType"
MaterialProcessElementList.vue ← name="aidopS0MfgMaterialProcessElement"
ManufacturingAggregatePage.vue/ManufacturingTodoPage.vue是 S0 的聚合展示页,暂不迁移(标注为后续补充)。
菜单 SeedData 追加(方法名 BuildS0ManufacturingMenus,SubDirId = 1329003000000L)
源文件参考路径(只读):
/home/yy968/work/s0/s0-operating-modeling/src/
api/modules/warehouse.js
views/warehouse/
LocationMaintenanceList.vue
DepartmentMaintenanceList.vue
EmployeeList.vue
RackList.vue
BarcodeRuleList.vue
LabelFormatList.vue
CostCenterList.vue
MaterialDutyList.vue
MaterialStatusTaskList.vue
OrderRuleList.vue
OrderTypeList.vue
PackagingSpecList.vue
WarehouseCrudPage.vue
WarehouseAggregatePage.vue
后端 — 新建实体(约 12 个):
Entity/S0/Warehouse/
AdoS0Location.cs → ado_s0_wh_location
AdoS0Department.cs → ado_s0_wh_department
AdoS0Employee.cs → ado_s0_wh_employee
AdoS0Rack.cs → ado_s0_wh_rack
AdoS0BarcodeRule.cs → ado_s0_wh_barcode_rule
AdoS0LabelFormat.cs → ado_s0_wh_label_format
AdoS0CostCenter.cs → ado_s0_wh_cost_center
AdoS0MaterialDuty.cs → ado_s0_wh_material_duty
AdoS0MaterialStatusTask.cs→ ado_s0_wh_material_status_task
AdoS0OrderRule.cs → ado_s0_wh_order_rule
AdoS0OrderType.cs → ado_s0_wh_order_type
AdoS0PackagingSpec.cs → ado_s0_wh_packaging_spec
菜单 SeedData 追加(方法名 BuildS0WarehouseMenus,SubDirId = 1329004000000L)
源文件参考路径(只读):
/home/yy968/work/s0/s0-operating-modeling/src/
api/modules/quality.js
views/quality/
AqlLevelList.vue
AqlValueList.vue
InspectionInstrumentList.vue
SamplingPlanList.vue
InspectionSchemeList.vue
DocumentTypeList.vue
BusinessTypeList.vue
InspectionMethodList.vue
QualityProjectTemplateList.vue
ComplaintCategoryList.vue
EightDTemplateList.vue
InspectionItemList.vue
InspectionPriorityList.vue
InspectionStandardList.vue
InspectionStatusList.vue
InspectionFrequencyList.vue
InspectionBasisList.vue
NcrDispositionTypeList.vue
NonconformanceContactTemplateList.vue
CapaTypeList.vue
RawMaterialSkipList.vue
后端 — 新建实体(约 16 个):
Entity/S0/Quality/
AdoS0AqlLevel.cs → ado_s0_qly_aql_level
AdoS0AqlValue.cs → ado_s0_qly_aql_value
AdoS0SamplingPlan.cs → ado_s0_qly_sampling_plan
AdoS0InspectionScheme.cs → ado_s0_qly_inspection_scheme
AdoS0InspectionInstrument.cs → ado_s0_qly_inspection_instrument
AdoS0InspectionMethod.cs → ado_s0_qly_inspection_method
AdoS0InspectionItem.cs → ado_s0_qly_inspection_item
AdoS0InspectionStandard.cs→ ado_s0_qly_inspection_standard
AdoS0DocumentType.cs → ado_s0_qly_document_type
AdoS0BusinessType.cs → ado_s0_qly_business_type
AdoS0ComplaintCategory.cs → ado_s0_qly_complaint_category
AdoS0NcrDispositionType.cs→ ado_s0_qly_ncr_disposition_type
AdoS0CapaType.cs → ado_s0_qly_capa_type
AdoS0InspectionPriority.cs→ ado_s0_qly_inspection_priority
AdoS0QualityProjectTemplate.cs → ado_s0_qly_project_template
AdoS0EightDTemplate.cs → ado_s0_qly_eight_d_template
菜单 SeedData 追加(方法名 BuildS0QualityMenus,SubDirId = 1329005000000L)
源文件参考路径(只读):
/home/yy968/work/s0/s0-operating-modeling/src/
api/modules/supply.js
views/supply/
SupplierList.vue
SourcingList.vue
后端 — 新建实体(约 4 个):
Entity/S0/Supply/
AdoS0Supplier.cs → ado_s0_supply_supplier
AdoS0Sourcing.cs → ado_s0_supply_sourcing
AdoS0SourcingItem.cs → ado_s0_supply_sourcing_item
AdoS0SupplierMaterial.cs → ado_s0_supply_supplier_material
菜单 SeedData 追加(方法名 BuildS0SupplyMenus,SubDirId = 1329006000000L)
源文件参考路径(只读):
/home/yy968/work/s0/s0-operating-modeling/src/
api/modules/business.js
views/business/
ProcessManagementList.vue
FormManagementList.vue
后端 — 新建实体(约 4 个):
Entity/S0/Business/
AdoS0ProcessDef.cs → ado_s0_biz_process_def
AdoS0ProcessNode.cs → ado_s0_biz_process_node
AdoS0FormTemplate.cs → ado_s0_biz_form_template
AdoS0FormField.cs → ado_s0_biz_form_field
菜单 SeedData 追加(方法名 BuildS0BusinessMenus,SubDirId = 1329007000000L)
每个 Batch 按如下顺序执行,未通过验收不得进入下一步:
Step 1 读取 S0 源文件 → 了解字段定义
Step 2 新建 Entity/*.cs → [SugarTable] + [SugarColumn] 格式
Step 3 新建 Dto/*.cs → Query/Upsert DTO
Step 4 新建 Controllers/*.cs → [AllowAnonymous][NonUnify] 插件风格
Step 5 修改 Startup.cs → InitTables 追加新实体类型
Step 6 新建 Web/src/views/aidop/s0/ → api/*.ts + views/*.vue (TS script setup)
Step 7 修改 SysMenuSeedData.cs → 追加 BuildS0XxxMenus() 私有方法
Step 8 执行验收 → 后端编译 + 表创建 + Swagger + 前端菜单 + CRUD
[AllowAnonymous] 上线前须收紧:所有 S0 Controller 目前都加 [AllowAnonymous],上线前统一换成 Admin.NET 的 [Authorize] 并配置角色权限。
Startup.cs using 语句:每批新增实体后,在 Startup.cs 顶部追加对应命名空间 using。
SeedData ID 唯一性:追加菜单时,每个 Id 在整个 SysMenuSeedData 范围内必须唯一,严格使用本文档的 ID 分配方案(1329xxx000000L 起)。
前端 AidopDemoShell 路径:页面在 s0/[module]/ 子目录下,相对路径为 ../../components/AidopDemoShell.vue。
跨实体下拉联动:如 Factory 依赖 Company、BomItem 依赖 Material,在对应页面中通过 api.list({pageSize:1000}) 拉取选项列表,赋值给 ref([]) 作为 el-select 的 options。
S0 源项目只读:迁移时只读取源代码作为参考,不修改 /home/yy968/work/s0/ 下任何文件。
表名前缀:所有 S0 新增表统一用 ado_s0_ 前缀,子模块缩写参照第五节分批计划表(platform / sales / mfg / wh / qly / supply / biz)。