瀏覽代碼

feat(s6): add production equipment ledger readonly list

- 新增 api/S6ProductionEquipmentLedger list(EquipmentList 单表直读,18 列映射)
- tenant_id 过滤:默认租户空态(正确隔离),数据租户 824585161322565 下 165 行
- productionEquipmentLedger.vue 骨架接真实接口(查询/分页/排序/空态)
- sbzt 中文 raw 展示;zyd A/B/C/D raw(中文映射后置)
- 无 MDP、无 SQL、无菜单变更;无新增/编辑/删除/启停用/状态流转
- 无打印/标签打印/导出;无部件明细(ems_jsjgcjsbzb 无归口表)
- 版本 server 1.0.229 / Web 2.4.224
YY968XX 1 周之前
父節點
當前提交
1d9faa4f0e

+ 1 - 1
Web/package.json

@@ -1,7 +1,7 @@
 {
   "name": "admin.net",
   "type": "module",
-  "version": "2.4.223",
+  "version": "2.4.224",
   "packageManager": "pnpm@10.32.1",
   "lastBuildTime": "2026.03.15",
   "description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",

+ 63 - 0
Web/src/views/aidop/s6/api/productionEquipmentLedger.ts

@@ -0,0 +1,63 @@
+import service from '/@/utils/request';
+import { withAidopTenantParams } from '../../api/aidopTenant';
+
+export interface Paged<T> {
+	total: number;
+	page: number;
+	pageSize: number;
+	list: T[];
+}
+
+// ── S6 生产设备台账(只读,数据源 aidopdev.EquipmentList 单表直读)──
+// 后端 Route api/S6ProductionEquipmentLedger;EquipmentList 有 tenant_id,后端按 tenant 过滤。
+export interface ProductionEquipmentLedgerRow {
+	id?: number;
+	/** 厂内设备名称 MachineName */
+	equipmentName?: string;
+	/** 设备识别码/资产编码 EquipmentAssetID */
+	equipmentIdentCode?: string;
+	/** 重要度 zyd(A/B/C/D) */
+	importance?: string;
+	/** 出厂日期 ccrq */
+	factoryDate?: string;
+	/** 额定功率 edgl */
+	ratedPower?: string;
+	/** 制造厂商 zzcs */
+	manufacturer?: string;
+	/** 车间 cj */
+	workshop?: string;
+	/** 保管人 bgr */
+	keeper?: string;
+	/** 标准维修天数 StandardRepairDays */
+	standard?: number;
+	/** 设备操作规程 sbczgc */
+	operationProcedure?: string;
+	/** 设备状态 sbzt(中文) */
+	equipmentStatus?: string;
+	/** 已服役年限 yfynx */
+	servedYears?: string;
+	/** 备注 bzm */
+	remark?: string;
+	/** 厂内设备编码 InternalEquipmentCode */
+	equipmentCode?: string;
+	/** 型号 xh */
+	model?: string;
+	/** 附件 fj */
+	attachment?: string;
+	/** 建议使用年限 jysynx */
+	suggestedUsageYears?: string;
+	/** 设备类型名称 TypeName */
+	equipmentTypeName?: string;
+	/** 班组 bz(默认不展示) */
+	team?: string;
+	/** 设备分类 sbfl(默认不展示) */
+	equipmentCategory?: string;
+	/** 可否排产 IsSchedulable(默认不展示) */
+	isSchedulable?: string;
+}
+
+export function fetchProductionEquipmentLedgerList(params: any) {
+	return service
+		.get<Paged<ProductionEquipmentLedgerRow>>('/api/S6ProductionEquipmentLedger/list', { params: withAidopTenantParams(params) })
+		.then((r) => r.data);
+}

+ 67 - 13
Web/src/views/aidop/s6/equipment-tooling/productionEquipmentLedger.vue

@@ -1,5 +1,11 @@
 <template>
 	<AidopDemoShell :title="pageTitle" subtitle="只读列表">
+		<!--
+			S6 生产设备台账 · 只读页(S6-PRODUCTION-EQUIPMENT-LEDGER-READONLY-LIST-1)。
+			数据源:aidopdev.EquipmentList(单表直读),后端 api/S6ProductionEquipmentLedger。
+			只读:无新增/编辑/删除/启停用/状态流转/打印/标签打印/导出/部件明细。
+			EquipmentList 有 tenant_id:默认租户下为空态基线;真实 165 行在租户 824585161322565。
+		-->
 		<el-form :inline="true" :model="query" class="mb12" @submit.prevent>
 			<el-form-item label="厂内设备名称">
 				<el-input v-model="query.equipmentName" clearable style="width: 200px" />
@@ -16,25 +22,27 @@
 			</el-form-item>
 		</el-form>
 
-		<el-table :data="rows" row-key="id" v-loading="loading" border stripe>
-			<el-table-column prop="equipmentName" label="厂内设备名称" min-width="150" show-overflow-tooltip resizable />
-			<el-table-column prop="equipmentIdentCode" label="设备识别码" min-width="130" show-overflow-tooltip resizable />
-			<el-table-column prop="importance" label="重要度" min-width="100" resizable />
-			<el-table-column prop="factoryDate" label="出厂日期" min-width="130" resizable />
+		<el-table :data="rows" row-key="id" v-loading="loading" border stripe @sort-change="onSortChange">
+			<el-table-column prop="equipmentName" label="厂内设备名称" min-width="150" sortable="custom" show-overflow-tooltip resizable />
+			<el-table-column prop="equipmentIdentCode" label="设备识别码" min-width="130" sortable="custom" show-overflow-tooltip resizable />
+			<el-table-column prop="importance" label="重要度" min-width="100" sortable="custom" resizable />
+			<el-table-column prop="factoryDate" label="出厂日期" min-width="130" sortable="custom" resizable>
+				<template #default="{ row }">{{ fmtDate(row.factoryDate) }}</template>
+			</el-table-column>
 			<el-table-column prop="ratedPower" label="额定功率" min-width="110" resizable />
 			<el-table-column prop="manufacturer" label="制造厂商" min-width="150" show-overflow-tooltip resizable />
 			<el-table-column prop="workshop" label="车间" min-width="110" show-overflow-tooltip resizable />
 			<el-table-column prop="keeper" label="保管人" min-width="110" show-overflow-tooltip resizable />
-			<el-table-column prop="standard" label="标准" min-width="100" resizable />
+			<el-table-column prop="standard" label="标准" min-width="100" align="right" sortable="custom" resizable />
 			<el-table-column prop="operationProcedure" label="设备操作规程" min-width="140" show-overflow-tooltip resizable />
-			<el-table-column prop="equipmentStatus" label="设备状态" min-width="110" resizable />
+			<el-table-column prop="equipmentStatus" label="设备状态" min-width="110" sortable="custom" resizable />
 			<el-table-column prop="servedYears" label="已服役年限" min-width="120" resizable />
 			<el-table-column prop="remark" label="备注" min-width="160" show-overflow-tooltip resizable />
-			<el-table-column prop="equipmentCode" label="厂内设备编码" min-width="140" show-overflow-tooltip resizable />
+			<el-table-column prop="equipmentCode" label="厂内设备编码" min-width="140" sortable="custom" show-overflow-tooltip resizable />
 			<el-table-column prop="model" label="型号" min-width="120" show-overflow-tooltip resizable />
-			<el-table-column prop="attachment" label="附件" min-width="100" resizable />
+			<el-table-column prop="attachment" label="附件" min-width="100" show-overflow-tooltip resizable />
 			<el-table-column prop="suggestedUsageYears" label="建议使用年限" min-width="130" resizable />
-			<el-table-column prop="equipmentTypeName" label="设备类型名称" min-width="140" show-overflow-tooltip resizable />
+			<el-table-column prop="equipmentTypeName" label="设备类型名称" min-width="140" sortable="custom" show-overflow-tooltip resizable />
 			<template #empty>
 				<el-empty description="暂无数据" />
 			</template>
@@ -47,15 +55,19 @@
 				:total="total"
 				:page-sizes="[10, 20, 50]"
 				layout="total, sizes, prev, pager, next"
+				@current-change="loadList"
+				@size-change="loadList"
 			/>
 		</div>
 	</AidopDemoShell>
 </template>
 
 <script setup lang="ts" name="aidopS6EquipmentToolingEquipmentLedger">
-import { computed, reactive, ref } from 'vue';
+import { computed, onActivated, onMounted, reactive, ref } from 'vue';
 import { useRoute } from 'vue-router';
+import { ElMessage } from 'element-plus';
 import AidopDemoShell from '/@/views/aidop/components/AidopDemoShell.vue';
+import { fetchProductionEquipmentLedgerList, type ProductionEquipmentLedgerRow } from '../api/productionEquipmentLedger';
 
 const route = useRoute();
 const pageTitle = computed(() => (route.meta?.title as string) || '生产设备台账');
@@ -66,15 +78,51 @@ const query = reactive({
 	assetCode: '',
 	page: 1,
 	pageSize: 10,
+	orderBy: '',
+	orderDir: '',
 });
 
-// 本批次为只读 UI 骨架,尚无真实生产设备台账接口:渲染空表,不发请求、不造数据。
 const loading = ref(false);
-const rows = ref<Record<string, unknown>[]>([]);
+const rows = ref<ProductionEquipmentLedgerRow[]>([]);
 const total = ref(0);
 
+function fmtDate(v?: string | null) {
+	if (!v) return '';
+	return String(v).slice(0, 10);
+}
+
+function onSortChange({ prop, order }: { prop: string; order: string | null }) {
+	query.orderBy = prop || '';
+	query.orderDir = order === 'ascending' ? 'asc' : order === 'descending' ? 'desc' : '';
+	loadList();
+}
+
+async function loadList() {
+	loading.value = true;
+	try {
+		const data = await fetchProductionEquipmentLedgerList({
+			equipmentName: query.equipmentName,
+			equipmentCode: query.equipmentCode,
+			equipmentAssetId: query.assetCode,
+			page: query.page,
+			pageSize: query.pageSize,
+			orderBy: query.orderBy,
+			orderDir: query.orderDir,
+		});
+		rows.value = data.list || [];
+		total.value = data.total || 0;
+	} catch (e: any) {
+		rows.value = [];
+		total.value = 0;
+		ElMessage.error(e?.message || '加载生产设备台账列表失败');
+	} finally {
+		loading.value = false;
+	}
+}
+
 function doSearch() {
 	query.page = 1;
+	loadList();
 }
 
 function resetQuery() {
@@ -82,7 +130,13 @@ function resetQuery() {
 	query.equipmentCode = '';
 	query.assetCode = '';
 	query.page = 1;
+	query.orderBy = '';
+	query.orderDir = '';
+	loadList();
 }
+
+onMounted(() => loadList());
+onActivated(() => loadList());
 </script>
 
 <style scoped lang="scss">

+ 3 - 3
server/Admin.NET.Web.Entry/Admin.NET.Web.Entry.csproj

@@ -11,9 +11,9 @@
     <GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
     <Copyright>Admin.NET</Copyright>
     <Description>Admin.NET ͨ��Ȩ�޿���ƽ̨</Description>
-    <AssemblyVersion>1.0.228</AssemblyVersion>
-    <FileVersion>1.0.228</FileVersion>
-    <Version>1.0.228</Version>
+    <AssemblyVersion>1.0.229</AssemblyVersion>
+    <FileVersion>1.0.229</FileVersion>
+    <Version>1.0.229</Version>
   </PropertyGroup>
 
   <ItemGroup>

+ 111 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/Manufacturing/Dto/ProductionEquipmentLedgerDto.cs

@@ -0,0 +1,111 @@
+namespace Admin.NET.Plugin.AiDOP.Manufacturing.Dto;
+
+/// <summary>
+/// S6 生产设备台账 查询入参(只读)。读 aidopdev.EquipmentList(单表直读)。
+/// EquipmentList 含 tenant_id:TenantId&gt;0 时按 tenant_id 过滤(默认租户下为空态,真实数据在 824585161322565)。
+/// </summary>
+public class ProductionEquipmentLedgerListInput
+{
+    /// <summary>页码(从 1 开始)</summary>
+    public int Page { get; set; } = 1;
+
+    /// <summary>每页条数</summary>
+    public int PageSize { get; set; } = 10;
+
+    /// <summary>厂内设备名称(EquipmentList.MachineName,模糊匹配)</summary>
+    public string? EquipmentName { get; set; }
+
+    /// <summary>厂内设备编码(EquipmentList.InternalEquipmentCode,模糊匹配)</summary>
+    public string? EquipmentCode { get; set; }
+
+    /// <summary>资产编码/设备识别码(EquipmentList.EquipmentAssetID,模糊匹配)</summary>
+    public string? EquipmentAssetId { get; set; }
+
+    /// <summary>排序字段(前端列 prop 白名单)</summary>
+    public string? OrderBy { get; set; }
+
+    /// <summary>排序方向(asc / desc)</summary>
+    public string? OrderDir { get; set; }
+
+    /// <summary>租户 ID(前端 withAidopTenantParams 注入;EquipmentList 有 tenant_id,&gt;0 时按其过滤,不绕过)</summary>
+    public long? TenantId { get; set; }
+}
+
+/// <summary>
+/// S6 生产设备台账 列表行(只读,扁平单表)。字段对齐现有骨架页列 prop(camelCase)。
+/// sbzt 已是中文文本 raw 展示;zyd 为 A/B/C/D 等级码 raw 展示(中文映射后置)。
+/// </summary>
+public class ProductionEquipmentLedgerListRow
+{
+    /// <summary>主键 id(EquipmentList.id)</summary>
+    public long Id { get; set; }
+
+    /// <summary>厂内设备名称(MachineName)</summary>
+    public string? EquipmentName { get; set; }
+
+    /// <summary>设备识别码/资产编码(EquipmentAssetID)</summary>
+    public string? EquipmentIdentCode { get; set; }
+
+    /// <summary>重要度(zyd,A/B/C/D raw)</summary>
+    public string? Importance { get; set; }
+
+    /// <summary>出厂日期(ccrq)</summary>
+    public string? FactoryDate { get; set; }
+
+    /// <summary>额定功率(edgl)</summary>
+    public string? RatedPower { get; set; }
+
+    /// <summary>制造厂商(zzcs)</summary>
+    public string? Manufacturer { get; set; }
+
+    /// <summary>车间/工作中心(cj)</summary>
+    public string? Workshop { get; set; }
+
+    /// <summary>保管人(bgr)</summary>
+    public string? Keeper { get; set; }
+
+    /// <summary>标准维修天数(StandardRepairDays)</summary>
+    public decimal? Standard { get; set; }
+
+    /// <summary>设备操作规程(sbczgc)</summary>
+    public string? OperationProcedure { get; set; }
+
+    /// <summary>设备状态(sbzt,中文 raw)</summary>
+    public string? EquipmentStatus { get; set; }
+
+    /// <summary>已服役年限(yfynx)</summary>
+    public string? ServedYears { get; set; }
+
+    /// <summary>备注(bzm)</summary>
+    public string? Remark { get; set; }
+
+    /// <summary>厂内设备编码(InternalEquipmentCode)</summary>
+    public string? EquipmentCode { get; set; }
+
+    /// <summary>型号(xh)</summary>
+    public string? Model { get; set; }
+
+    /// <summary>附件(fj)</summary>
+    public string? Attachment { get; set; }
+
+    /// <summary>建议使用年限(jysynx)</summary>
+    public string? SuggestedUsageYears { get; set; }
+
+    /// <summary>设备类型名称(TypeName)</summary>
+    public string? EquipmentTypeName { get; set; }
+
+    /// <summary>班组(bz;DTO 保留,前端默认不展示)</summary>
+    public string? Team { get; set; }
+
+    /// <summary>设备分类(sbfl;DTO 保留,前端默认不展示)</summary>
+    public string? EquipmentCategory { get; set; }
+
+    /// <summary>可否排产(IsSchedulable;DTO 保留,前端默认不展示)</summary>
+    public string? IsSchedulable { get; set; }
+
+    /// <summary>预计维修释放时间(EstimatedMaintenanceReleaseTime;DTO 保留,前端默认不展示)</summary>
+    public string? EstimatedMaintenanceReleaseTime { get; set; }
+
+    /// <summary>租户 ID(tenant_id;DTO 保留,前端默认不展示)</summary>
+    public long? TenantId { get; set; }
+}

+ 133 - 0
server/Plugins/Admin.NET.Plugin.AiDOP/Manufacturing/ProductionEquipmentLedgerService.cs

@@ -0,0 +1,133 @@
+using Admin.NET.Plugin.AiDOP.Manufacturing.Dto;
+
+namespace Admin.NET.Plugin.AiDOP.Manufacturing;
+
+/// <summary>
+/// S6 生产设备台账 只读 list 服务。
+///
+/// 数据源:aidopdev.EquipmentList(设备台账主表,单表直读,无 join)。
+/// 参考本仓既有直读 + 接骨架范式:S7 FinishedWarehouse/ProductionInboundService、S5 LabelQueryService。
+///
+/// 本服务仅 SELECT:无新增/编辑/删除/启停用/状态流转/打印/标签打印/导出/部件明细;不写 EquipmentList;不建 MDP。
+/// EquipmentList 含 tenant_id:TenantId&gt;0 时按 tenant_id 过滤(不绕过)。当前 165 行全在 tenant 824585161322565;
+/// 默认租户 1300000000001 下 total=0 为正确隔离;真实数据渲染需切到 824585161322565。
+/// sbzt 已是中文文本 raw 展示;zyd 为 A/B/C/D 等级码 raw 展示(中文映射后置)。
+/// </summary>
+[ApiDescriptionSettings(Order = 311, Description = "生产设备台账")]
+[Route("api/S6ProductionEquipmentLedger")]
+[AllowAnonymous]
+[NonUnify]
+public class ProductionEquipmentLedgerService : IDynamicApiController, ITransient
+{
+    private readonly ISqlSugarClient _db;
+
+    public ProductionEquipmentLedgerService(ISqlSugarClient db)
+    {
+        _db = db;
+    }
+
+    /// <summary>
+    /// 生产设备台账列表(只读分页查询)。
+    /// </summary>
+    [DisplayName("生产设备台账列表")]
+    [HttpGet("list")]
+    public async Task<object> GetList([FromQuery] ProductionEquipmentLedgerListInput input)
+    {
+        var page = input.Page <= 0 ? 1 : input.Page;
+        var pageSize = input.PageSize <= 0 ? 10 : input.PageSize;
+        if (pageSize > 200) pageSize = 200;
+        var offset = (page - 1) * pageSize;
+
+        var where = new List<string> { "1=1" };
+        var pars = new List<SugarParameter>();
+
+        if (input.TenantId is > 0)
+        {
+            where.Add("m.tenant_id = @TenantId");
+            pars.Add(new SugarParameter("@TenantId", input.TenantId));
+        }
+        if (!string.IsNullOrWhiteSpace(input.EquipmentName))
+        {
+            where.Add("m.MachineName LIKE @EquipmentName");
+            pars.Add(new SugarParameter("@EquipmentName", $"%{input.EquipmentName.Trim()}%"));
+        }
+        if (!string.IsNullOrWhiteSpace(input.EquipmentCode))
+        {
+            where.Add("m.InternalEquipmentCode LIKE @EquipmentCode");
+            pars.Add(new SugarParameter("@EquipmentCode", $"%{input.EquipmentCode.Trim()}%"));
+        }
+        if (!string.IsNullOrWhiteSpace(input.EquipmentAssetId))
+        {
+            where.Add("m.EquipmentAssetID LIKE @EquipmentAssetId");
+            pars.Add(new SugarParameter("@EquipmentAssetId", $"%{input.EquipmentAssetId.Trim()}%"));
+        }
+
+        var whereSql = string.Join(" AND ", where);
+
+        var total = await _db.Ado.GetIntAsync(
+            $"SELECT COUNT(1) FROM EquipmentList m WHERE {whereSql}", pars);
+
+        var list = await _db.Ado.SqlQueryAsync<ProductionEquipmentLedgerListRow>(
+            $"""
+            SELECT
+                m.id                              AS Id,
+                m.MachineName                     AS EquipmentName,
+                m.EquipmentAssetID                AS EquipmentIdentCode,
+                m.zyd                             AS Importance,
+                m.ccrq                            AS FactoryDate,
+                m.edgl                            AS RatedPower,
+                m.zzcs                            AS Manufacturer,
+                m.cj                              AS Workshop,
+                m.bgr                             AS Keeper,
+                m.StandardRepairDays              AS Standard,
+                m.sbczgc                          AS OperationProcedure,
+                m.sbzt                            AS EquipmentStatus,
+                m.yfynx                           AS ServedYears,
+                m.bzm                             AS Remark,
+                m.InternalEquipmentCode           AS EquipmentCode,
+                m.xh                              AS Model,
+                m.fj                              AS Attachment,
+                m.jysynx                          AS SuggestedUsageYears,
+                m.TypeName                        AS EquipmentTypeName,
+                m.bz                              AS Team,
+                m.sbfl                            AS EquipmentCategory,
+                m.IsSchedulable                   AS IsSchedulable,
+                m.EstimatedMaintenanceReleaseTime AS EstimatedMaintenanceReleaseTime,
+                m.tenant_id                       AS TenantId
+            FROM EquipmentList m
+            WHERE {whereSql}
+            ORDER BY {BuildOrderBy(input.OrderBy, input.OrderDir)}
+            LIMIT {pageSize} OFFSET {offset}
+            """,
+            pars);
+
+        return new { total, page, pageSize, list };
+    }
+
+    /// <summary>
+    /// 排序白名单:仅允许按已展示列排序,杜绝 SQL 注入;非法字段回落默认。
+    /// </summary>
+    private static string BuildOrderBy(string? orderBy, string? orderDir)
+    {
+        var column = orderBy switch
+        {
+            "equipmentName" => "m.MachineName",
+            "equipmentCode" => "m.InternalEquipmentCode",
+            "equipmentIdentCode" => "m.EquipmentAssetID",
+            "importance" => "m.zyd",
+            "factoryDate" => "m.ccrq",
+            "ratedPower" => "m.edgl",
+            "manufacturer" => "m.zzcs",
+            "workshop" => "m.cj",
+            "keeper" => "m.bgr",
+            "standard" => "m.StandardRepairDays",
+            "equipmentStatus" => "m.sbzt",
+            "servedYears" => "m.yfynx",
+            "suggestedUsageYears" => "m.jysynx",
+            "equipmentTypeName" => "m.TypeName",
+            _ => "m.id",
+        };
+        var direction = string.Equals(orderDir, "asc", StringComparison.OrdinalIgnoreCase) ? "ASC" : "DESC";
+        return $"{column} {direction}, m.id DESC";
+    }
+}