更新MybatisPlusSaasConfig中的租户ID默认值为1002;在ShiroConfig中添加MES密炼物料管理和系统分类字典的免密接口;在MesMixerMaterialController中实现密炼物料信息的免密增删改查接口,并添加相应的事件广播功能;在SysCategoryController中新增分类字典的免密查询接口;更新前端导航和菜单数据以支持密炼物料信息模块。
This commit is contained in:
@@ -113,7 +113,7 @@ public class MybatisPlusSaasConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (oConvertUtils.isEmpty(tenantId)) {
|
if (oConvertUtils.isEmpty(tenantId)) {
|
||||||
tenantId = "0";
|
tenantId = "1002";
|
||||||
}
|
}
|
||||||
return new LongValue(tenantId);
|
return new LongValue(tenantId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -203,6 +203,10 @@ public class ShiroConfig {
|
|||||||
filterChainDefinitionMap.put("/xslmes/mesXslSupplier/anon/**", "anon");
|
filterChainDefinitionMap.put("/xslmes/mesXslSupplier/anon/**", "anon");
|
||||||
// MES磅单管理免密接口(供桌面端调用)
|
// MES磅单管理免密接口(供桌面端调用)
|
||||||
filterChainDefinitionMap.put("/xslmes/mesXslWeightRecord/anon/**", "anon");
|
filterChainDefinitionMap.put("/xslmes/mesXslWeightRecord/anon/**", "anon");
|
||||||
|
// MES密炼物料管理免密接口(供桌面端调用)
|
||||||
|
filterChainDefinitionMap.put("/mes/material/mixerMaterial/anon/**", "anon");
|
||||||
|
// 系统分类字典免密接口(供桌面端调用)
|
||||||
|
filterChainDefinitionMap.put("/sys/category/anon/**", "anon");
|
||||||
// 桌面端用户反同步批量上报(Outbox -> /sys/sync/batch)
|
// 桌面端用户反同步批量上报(Outbox -> /sys/sync/batch)
|
||||||
filterChainDefinitionMap.put("/sys/sync/batch", "anon");
|
filterChainDefinitionMap.put("/sys/sync/batch", "anon");
|
||||||
|
|
||||||
|
|||||||
@@ -40,6 +40,11 @@ public class MesXslStompNotifyService {
|
|||||||
publish("/topic/sync/mes-weight-records", "MES_WEIGHT_RECORD_CHANGED", "weightRecordId", weightRecordId, action);
|
publish("/topic/sync/mes-weight-records", "MES_WEIGHT_RECORD_CHANGED", "weightRecordId", weightRecordId, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 广播密炼物料数据变更事件到 /topic/sync/mes-mixer-materials */
|
||||||
|
public void publishMixerMaterialChanged(String action, String mixerMaterialId) {
|
||||||
|
publish("/topic/sync/mes-mixer-materials", "MIXER_MATERIAL_CHANGED", "mixerMaterialId", mixerMaterialId, action);
|
||||||
|
}
|
||||||
|
|
||||||
// ─────────────────────────── 私有辅助 ────────────────────────────
|
// ─────────────────────────── 私有辅助 ────────────────────────────
|
||||||
|
|
||||||
private void publish(String topic, String cmd, String idKey, String idValue, String action) {
|
private void publish(String topic, String cmd, String idKey, String idValue, String action) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.jeecg.modules.mes.material.controller;
|
package org.jeecg.modules.mes.material.controller;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
@@ -17,14 +18,23 @@ import org.jeecg.common.system.base.controller.JeecgController;
|
|||||||
import org.jeecg.common.system.query.QueryGenerator;
|
import org.jeecg.common.system.query.QueryGenerator;
|
||||||
import org.jeecg.modules.mes.material.entity.MesMixerMaterial;
|
import org.jeecg.modules.mes.material.entity.MesMixerMaterial;
|
||||||
import org.jeecg.modules.mes.material.service.IMesMixerMaterialService;
|
import org.jeecg.modules.mes.material.service.IMesMixerMaterialService;
|
||||||
|
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Tag(name = "MES-密炼物料信息")
|
@Tag(name = "MES-密炼物料信息")
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/mes/material/mixerMaterial")
|
@RequestMapping("/mes/material/mixerMaterial")
|
||||||
public class MesMixerMaterialController extends JeecgController<MesMixerMaterial, IMesMixerMaterialService> {
|
public class MesMixerMaterialController extends JeecgController<MesMixerMaterial, IMesMixerMaterialService> {
|
||||||
|
private final SimpMessagingTemplate messagingTemplate;
|
||||||
|
|
||||||
|
public MesMixerMaterialController(SimpMessagingTemplate messagingTemplate) {
|
||||||
|
this.messagingTemplate = messagingTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping("/list")
|
@GetMapping("/list")
|
||||||
public Result<IPage<MesMixerMaterial>> queryPageList(
|
public Result<IPage<MesMixerMaterial>> queryPageList(
|
||||||
@@ -43,6 +53,7 @@ public class MesMixerMaterialController extends JeecgController<MesMixerMaterial
|
|||||||
@PostMapping("/add")
|
@PostMapping("/add")
|
||||||
public Result<String> add(@RequestBody MesMixerMaterial model) {
|
public Result<String> add(@RequestBody MesMixerMaterial model) {
|
||||||
service.save(model);
|
service.save(model);
|
||||||
|
publishChanged("add", model.getId());
|
||||||
return Result.OK("添加成功!");
|
return Result.OK("添加成功!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,6 +63,7 @@ public class MesMixerMaterialController extends JeecgController<MesMixerMaterial
|
|||||||
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
||||||
public Result<String> edit(@RequestBody MesMixerMaterial model) {
|
public Result<String> edit(@RequestBody MesMixerMaterial model) {
|
||||||
service.updateById(model);
|
service.updateById(model);
|
||||||
|
publishChanged("edit", model.getId());
|
||||||
return Result.OK("编辑成功!");
|
return Result.OK("编辑成功!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,6 +73,7 @@ public class MesMixerMaterialController extends JeecgController<MesMixerMaterial
|
|||||||
@DeleteMapping("/delete")
|
@DeleteMapping("/delete")
|
||||||
public Result<String> delete(@RequestParam(name = "id") String id) {
|
public Result<String> delete(@RequestParam(name = "id") String id) {
|
||||||
service.removeById(id);
|
service.removeById(id);
|
||||||
|
publishChanged("delete", id);
|
||||||
return Result.OK("删除成功!");
|
return Result.OK("删除成功!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,6 +84,62 @@ public class MesMixerMaterialController extends JeecgController<MesMixerMaterial
|
|||||||
public Result<String> deleteBatch(@RequestParam(name = "ids") String ids) {
|
public Result<String> deleteBatch(@RequestParam(name = "ids") String ids) {
|
||||||
List<String> idList = Arrays.asList(ids.split(","));
|
List<String> idList = Arrays.asList(ids.split(","));
|
||||||
service.removeByIds(idList);
|
service.removeByIds(idList);
|
||||||
|
publishChanged("batchDelete", ids);
|
||||||
|
return Result.OK("批量删除成功!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "MES-密炼物料信息-免密分页查询")
|
||||||
|
@GetMapping("/anon/list")
|
||||||
|
public Result<IPage<MesMixerMaterial>> anonList(
|
||||||
|
MesMixerMaterial model,
|
||||||
|
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
|
||||||
|
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
|
||||||
|
HttpServletRequest req) {
|
||||||
|
QueryWrapper<MesMixerMaterial> queryWrapper = QueryGenerator.initQueryWrapper(model, req.getParameterMap());
|
||||||
|
IPage<MesMixerMaterial> pageList = service.page(new Page<>(pageNo, pageSize), queryWrapper);
|
||||||
|
return Result.OK(pageList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "MES-密炼物料信息-免密通过id查询")
|
||||||
|
@GetMapping("/anon/queryById")
|
||||||
|
public Result<MesMixerMaterial> anonQueryById(@RequestParam(name = "id") String id) {
|
||||||
|
MesMixerMaterial data = service.getById(id);
|
||||||
|
return data != null ? Result.OK(data) : Result.error("未找到对应数据");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "MES-密炼物料信息-免密添加")
|
||||||
|
@PostMapping("/anon/add")
|
||||||
|
public Result<String> anonAdd(@RequestBody MesMixerMaterial model) {
|
||||||
|
service.save(model);
|
||||||
|
publishChanged("add", model.getId());
|
||||||
|
return Result.OK("添加成功!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "MES-密炼物料信息-免密编辑")
|
||||||
|
@RequestMapping(value = "/anon/edit", method = {RequestMethod.PUT, RequestMethod.POST})
|
||||||
|
public Result<String> anonEdit(@RequestBody MesMixerMaterial model) {
|
||||||
|
boolean ok = service.updateById(model);
|
||||||
|
if (!ok) {
|
||||||
|
return Result.error("数据已被他人修改,请刷新后重试");
|
||||||
|
}
|
||||||
|
publishChanged("edit", model.getId());
|
||||||
|
return Result.OK("编辑成功!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "MES-密炼物料信息-免密删除")
|
||||||
|
@DeleteMapping("/anon/delete")
|
||||||
|
public Result<String> anonDelete(@RequestParam(name = "id") String id) {
|
||||||
|
service.removeById(id);
|
||||||
|
publishChanged("delete", id);
|
||||||
|
return Result.OK("删除成功!");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(summary = "MES-密炼物料信息-免密批量删除")
|
||||||
|
@DeleteMapping("/anon/deleteBatch")
|
||||||
|
public Result<String> anonDeleteBatch(@RequestParam(name = "ids") String ids) {
|
||||||
|
List<String> idList = Arrays.asList(ids.split(","));
|
||||||
|
service.removeByIds(idList);
|
||||||
|
publishChanged("batchDelete", ids);
|
||||||
return Result.OK("批量删除成功!");
|
return Result.OK("批量删除成功!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,4 +159,17 @@ public class MesMixerMaterialController extends JeecgController<MesMixerMaterial
|
|||||||
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
|
public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {
|
||||||
return super.importExcel(request, response, MesMixerMaterial.class);
|
return super.importExcel(request, response, MesMixerMaterial.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void publishChanged(String action, String mixerMaterialId) {
|
||||||
|
try {
|
||||||
|
Map<String, Object> event = new HashMap<>();
|
||||||
|
event.put("cmd", "MIXER_MATERIAL_CHANGED");
|
||||||
|
event.put("action", action);
|
||||||
|
event.put("mixerMaterialId", mixerMaterialId);
|
||||||
|
event.put("timestamp", System.currentTimeMillis());
|
||||||
|
messagingTemplate.convertAndSend("/topic/sync/mes-mixer-materials", JSON.toJSONString(event));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("广播密炼物料 STOMP 事件失败: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -482,6 +482,78 @@ public class SysCategoryController {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类字典树控件(免密)加载节点
|
||||||
|
*/
|
||||||
|
@RequestMapping(value = "/anon/loadTreeData", method = RequestMethod.GET)
|
||||||
|
public Result<List<TreeSelectModel>> anonLoadDict(@RequestParam(name="pid",required = false) String pid,@RequestParam(name="pcode",required = false) String pcode, @RequestParam(name="condition",required = false) String condition) {
|
||||||
|
Result<List<TreeSelectModel>> result = new Result<List<TreeSelectModel>>();
|
||||||
|
String queryPid = pid;
|
||||||
|
if (oConvertUtils.isEmpty(queryPid)) {
|
||||||
|
if (oConvertUtils.isEmpty(pcode) || ISysCategoryService.ROOT_PID_VALUE.equals(pcode)) {
|
||||||
|
queryPid = ISysCategoryService.ROOT_PID_VALUE;
|
||||||
|
} else {
|
||||||
|
queryPid = this.sysCategoryService.queryIdByCode(pcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (oConvertUtils.isEmpty(queryPid)) {
|
||||||
|
result.setSuccess(false);
|
||||||
|
result.setMessage("加载分类字典树参数有误.[code]!");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryWrapper<SysCategory> queryWrapper = new QueryWrapper<>();
|
||||||
|
if (ISysCategoryService.ROOT_PID_VALUE.equals(queryPid)) {
|
||||||
|
queryWrapper.and(w -> w.eq("pid", ISysCategoryService.ROOT_PID_VALUE).or().isNull("pid"));
|
||||||
|
} else {
|
||||||
|
queryWrapper.eq("pid", queryPid);
|
||||||
|
}
|
||||||
|
queryWrapper.orderByAsc("code");
|
||||||
|
List<SysCategory> categories = this.sysCategoryService.list(queryWrapper);
|
||||||
|
List<TreeSelectModel> list = new ArrayList<>();
|
||||||
|
for (SysCategory c : categories) {
|
||||||
|
TreeSelectModel tsm = new TreeSelectModel();
|
||||||
|
tsm.setKey(c.getId());
|
||||||
|
tsm.setValue(c.getId());
|
||||||
|
tsm.setTitle(c.getName());
|
||||||
|
tsm.setParentId(c.getPid());
|
||||||
|
tsm.setCode(c.getCode());
|
||||||
|
tsm.setLeaf(!CommonConstant.STATUS_1.equals(c.getHasChild()));
|
||||||
|
list.add(tsm);
|
||||||
|
}
|
||||||
|
result.setSuccess(true);
|
||||||
|
result.setResult(list);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类字典子节点(免密)
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/anon/childList")
|
||||||
|
public Result<List<SysCategory>> anonChildList(SysCategory sysCategory, HttpServletRequest req) {
|
||||||
|
Result<List<SysCategory>> result = new Result<List<SysCategory>>();
|
||||||
|
String pid = sysCategory.getPid();
|
||||||
|
QueryWrapper<SysCategory> queryWrapper = new QueryWrapper<>();
|
||||||
|
if (oConvertUtils.isEmpty(pid) || ISysCategoryService.ROOT_PID_VALUE.equals(pid)) {
|
||||||
|
queryWrapper.and(w -> w.eq("pid", ISysCategoryService.ROOT_PID_VALUE).or().isNull("pid"));
|
||||||
|
} else {
|
||||||
|
queryWrapper.eq("pid", pid);
|
||||||
|
}
|
||||||
|
queryWrapper.orderByAsc("code");
|
||||||
|
List<SysCategory> list = this.sysCategoryService.list(queryWrapper);
|
||||||
|
result.setSuccess(true);
|
||||||
|
result.setResult(list);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分类字典详情(免密)
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/anon/queryById")
|
||||||
|
public Result<SysCategory> anonQueryById(@RequestParam(name="id",required=true) String id) {
|
||||||
|
return queryById(id);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分类字典控件数据回显[表单页面]
|
* 分类字典控件数据回显[表单页面]
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using Prism.Events;
|
||||||
|
|
||||||
|
namespace YY.Admin.Core.Events;
|
||||||
|
|
||||||
|
public class MixerMaterialChangedPayload
|
||||||
|
{
|
||||||
|
public string Action { get; set; } = string.Empty;
|
||||||
|
public string? MixerMaterialId { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MixerMaterialChangedEvent : PubSubEvent<MixerMaterialChangedPayload> { }
|
||||||
|
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
using YY.Admin.Core.Entity;
|
||||||
|
|
||||||
|
namespace YY.Admin.Core.Services;
|
||||||
|
|
||||||
|
public record MixerMaterialPageResult(List<MesMixerMaterial> Records, long Total, int Current, int Size);
|
||||||
|
|
||||||
|
public interface IMixerMaterialService
|
||||||
|
{
|
||||||
|
Task<MixerMaterialPageResult> PageAsync(
|
||||||
|
int pageNo,
|
||||||
|
int pageSize,
|
||||||
|
string? materialCode = null,
|
||||||
|
string? materialName = null,
|
||||||
|
string? erpCode = null,
|
||||||
|
string? majorCategoryId = null,
|
||||||
|
string? minorCategoryId = null,
|
||||||
|
CancellationToken ct = default);
|
||||||
|
|
||||||
|
Task<MesMixerMaterial?> GetByIdAsync(string id, CancellationToken ct = default);
|
||||||
|
Task<bool> AddAsync(MesMixerMaterial material, CancellationToken ct = default);
|
||||||
|
Task<bool> EditAsync(MesMixerMaterial material, CancellationToken ct = default);
|
||||||
|
Task<bool> DeleteAsync(string id, CancellationToken ct = default);
|
||||||
|
Task<bool> DeleteBatchAsync(string ids, CancellationToken ct = default);
|
||||||
|
Task<List<KeyValuePair<string, string>>> GetMajorCategoryOptionsAsync(CancellationToken ct = default);
|
||||||
|
Task<List<KeyValuePair<string, string>>> GetMinorCategoryOptionsAsync(string majorCategoryId, CancellationToken ct = default);
|
||||||
|
}
|
||||||
|
|
||||||
38
yy-admin-master/YY.Admin.Core/Entity/JeecgSysCategoryItem.cs
Normal file
38
yy-admin-master/YY.Admin.Core/Entity/JeecgSysCategoryItem.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
namespace YY.Admin.Core.Entity;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Jeecg 分类字典镜像表
|
||||||
|
/// </summary>
|
||||||
|
[SugarTable("jeecg_sys_category_item", "Jeecg分类字典镜像表")]
|
||||||
|
[SysTable]
|
||||||
|
[SugarIndex("index_{table}_PC", nameof(Pid), OrderByType.Asc, nameof(Code), OrderByType.Asc)]
|
||||||
|
public class JeecgSysCategoryItem
|
||||||
|
{
|
||||||
|
[SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键ID", Length = 64)]
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
[SugarColumn(ColumnDescription = "父ID", Length = 64)]
|
||||||
|
public string? Pid { get; set; }
|
||||||
|
|
||||||
|
[SugarColumn(ColumnDescription = "分类名称", Length = 128)]
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
|
[SugarColumn(ColumnDescription = "分类编码", Length = 128)]
|
||||||
|
public string? Code { get; set; }
|
||||||
|
|
||||||
|
[SugarColumn(ColumnDescription = "是否有子节点", Length = 1)]
|
||||||
|
public string? HasChild { get; set; }
|
||||||
|
|
||||||
|
[SugarColumn(ColumnDescription = "创建人", Length = 64)]
|
||||||
|
public string? CreateBy { get; set; }
|
||||||
|
|
||||||
|
[SugarColumn(ColumnDescription = "创建时间")]
|
||||||
|
public DateTime? CreateTime { get; set; }
|
||||||
|
|
||||||
|
[SugarColumn(ColumnDescription = "更新人", Length = 64)]
|
||||||
|
public string? UpdateBy { get; set; }
|
||||||
|
|
||||||
|
[SugarColumn(ColumnDescription = "更新时间")]
|
||||||
|
public DateTime? UpdateTime { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
40
yy-admin-master/YY.Admin.Core/Entity/MesMixerMaterial.cs
Normal file
40
yy-admin-master/YY.Admin.Core/Entity/MesMixerMaterial.cs
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace YY.Admin.Core.Entity;
|
||||||
|
|
||||||
|
public class MesMixerMaterial
|
||||||
|
{
|
||||||
|
public string? Id { get; set; }
|
||||||
|
public string? MaterialCode { get; set; }
|
||||||
|
public string? MaterialName { get; set; }
|
||||||
|
public string? ErpCode { get; set; }
|
||||||
|
public string? MajorCategoryId { get; set; }
|
||||||
|
public string? MinorCategoryId { get; set; }
|
||||||
|
public string? MaterialDesc { get; set; }
|
||||||
|
public string? AliasName { get; set; }
|
||||||
|
public int? FeedManageStatus { get; set; }
|
||||||
|
public int? UseStatus { get; set; }
|
||||||
|
public double? SpecificGravity { get; set; }
|
||||||
|
public int? ShelfLifeDays { get; set; }
|
||||||
|
public int? MinBakeMinutes { get; set; }
|
||||||
|
public double? TotalSafetyStockKg { get; set; }
|
||||||
|
public double? QualifiedSafetyStockKg { get; set; }
|
||||||
|
public string? Remark { get; set; }
|
||||||
|
public int? TenantId { get; set; }
|
||||||
|
public string? SysOrgCode { get; set; }
|
||||||
|
public string? CreateBy { get; set; }
|
||||||
|
public DateTime? CreateTime { get; set; }
|
||||||
|
public string? UpdateBy { get; set; }
|
||||||
|
public DateTime? UpdateTime { get; set; }
|
||||||
|
public int? DelFlag { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("majorCategoryId_dictText")]
|
||||||
|
public string? MajorCategoryText { get; set; }
|
||||||
|
|
||||||
|
[JsonPropertyName("minorCategoryId_dictText")]
|
||||||
|
public string? MinorCategoryText { get; set; }
|
||||||
|
|
||||||
|
public string FeedManageStatusText => FeedManageStatus == 1 ? "在投管" : "未投管";
|
||||||
|
public string UseStatusText => UseStatus == 1 ? "使用中" : "停用";
|
||||||
|
}
|
||||||
|
|
||||||
@@ -36,6 +36,8 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
|
|||||||
new SysMenu{ Id=1300150010401, Pid=1300150000101, Title="磅单记录管理", Path="/xslmes/mesXslWeightRecord", Name="mesXslWeightRecord", Component="WeightRecordListView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=103 },
|
new SysMenu{ Id=1300150010401, Pid=1300150000101, Title="磅单记录管理", Path="/xslmes/mesXslWeightRecord", Name="mesXslWeightRecord", Component="WeightRecordListView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=103 },
|
||||||
// 地磅称重操作(操作台大页面)
|
// 地磅称重操作(操作台大页面)
|
||||||
new SysMenu{ Id=1300150010501, Pid=1300150000101, Title="地磅称重操作", Path="/xslmes/weightRecordOperation", Name="weightRecordOperation", Component="WeightRecordOperationView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=104 },
|
new SysMenu{ Id=1300150010501, Pid=1300150000101, Title="地磅称重操作", Path="/xslmes/weightRecordOperation", Name="weightRecordOperation", Component="WeightRecordOperationView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=104 },
|
||||||
|
// 密炼物料信息
|
||||||
|
new SysMenu{ Id=1300150010601, Pid=1300150000101, Title="密炼物料信息", Path="/xslmes/mesMixerMaterial", Name="mesMixerMaterial", Component="MixerMaterialListView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=105 },
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -60,6 +62,10 @@ public class SysMenuSeedData : ISqlSugarEntitySeedData<SysMenu>
|
|||||||
new SysMenu{ Id=1300200012001, Pid=1300200000101, Title="数据字典", Path="DataDictionaryManagementView", Name="sysDict", Component="/system/dict/index", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=105 },
|
new SysMenu{ Id=1300200012001, Pid=1300200000101, Title="数据字典", Path="DataDictionaryManagementView", Name="sysDict", Component="/system/dict/index", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=105 },
|
||||||
new SysMenu{ Id=1300200012011, Pid=1300200012001, Title="查询", Permission="sysDict:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
new SysMenu{ Id=1300200012011, Pid=1300200012001, Title="查询", Permission="sysDict:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||||
new SysMenu{ Id=1300200012021, Pid=1300200012001, Title="同步", Permission="sysDict:sync", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
new SysMenu{ Id=1300200012021, Pid=1300200012001, Title="同步", Permission="sysDict:sync", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||||
|
// 分类字典(SCADA同步)
|
||||||
|
new SysMenu{ Id=1300200012101, Pid=1300200000101, Title="分类字典", Path="CategoryDictionaryManagementView", Name="sysCategory", Component="/system/category/index", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=106 },
|
||||||
|
new SysMenu{ Id=1300200012111, Pid=1300200012101, Title="查询", Permission="sysCategory:page", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||||
|
new SysMenu{ Id=1300200012121, Pid=1300200012101, Title="同步", Permission="sysCategory:sync", Type=MenuTypeEnum.Btn, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=100 },
|
||||||
|
|
||||||
// 登录设置(桌面端会话与检查间隔)
|
// 登录设置(桌面端会话与检查间隔)
|
||||||
new SysMenu{ Id=1300200013001, Pid=1300200000101, Title="登录设置", Path="LoginSettingsView", Name="loginSettings", Component="LoginSettingsView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=107 },
|
new SysMenu{ Id=1300200013001, Pid=1300200000101, Title="登录设置", Path="LoginSettingsView", Name="loginSettings", Component="LoginSettingsView", Icon="", Type=MenuTypeEnum.Menu, CreateTime=DateTime.Parse("2022-02-10 00:00:00"), OrderNo=107 },
|
||||||
|
|||||||
@@ -26,6 +26,10 @@ public class SysTenantMenuSeedData : ISqlSugarEntitySeedData<SysTenantMenu>
|
|||||||
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150010201},
|
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150010201},
|
||||||
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150010401},
|
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150010401},
|
||||||
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150010501},
|
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150010501},
|
||||||
|
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300150010601},
|
||||||
|
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012101},
|
||||||
|
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012111},
|
||||||
|
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200012121},
|
||||||
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200010701 },
|
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200010701 },
|
||||||
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300300100601 },
|
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300300100601 },
|
||||||
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200090401 },
|
new SysTenantMenu(){ TenantId=1300000000001,MenuId=1300200090401 },
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
namespace YY.Admin.Services.Service.Category.Dto;
|
||||||
|
|
||||||
|
public class JeecgCategoryItemOutput
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public string? Pid { get; set; }
|
||||||
|
public string? Name { get; set; }
|
||||||
|
public string? Code { get; set; }
|
||||||
|
public string? HasChild { get; set; }
|
||||||
|
public DateTime? CreateTime { get; set; }
|
||||||
|
public DateTime? UpdateTime { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace YY.Admin.Services.Service.Category.Dto;
|
||||||
|
|
||||||
|
public class JeecgCategoryTreeNodeDto
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public string? Pid { get; set; }
|
||||||
|
public string? Name { get; set; }
|
||||||
|
public string? Code { get; set; }
|
||||||
|
public List<JeecgCategoryTreeNodeDto> Children { get; set; } = [];
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace YY.Admin.Services.Service.Category.Dto;
|
||||||
|
|
||||||
|
public class PageJeecgCategoryItemInput
|
||||||
|
{
|
||||||
|
public int Page { get; set; } = 1;
|
||||||
|
public int PageSize { get; set; } = 20;
|
||||||
|
public string? Name { get; set; }
|
||||||
|
public string? Code { get; set; }
|
||||||
|
public string? Pid { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using YY.Admin.Services.Service.Category.Dto;
|
||||||
|
|
||||||
|
namespace YY.Admin.Services.Service.Category;
|
||||||
|
|
||||||
|
public interface IJeecgCategorySyncService
|
||||||
|
{
|
||||||
|
Task<SqlSugarPagedList<JeecgCategoryItemOutput>> PageAsync(PageJeecgCategoryItemInput input);
|
||||||
|
Task<int> SyncFromJeecgAsync();
|
||||||
|
Task<List<JeecgCategoryTreeNodeDto>> LoadTreeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,240 @@
|
|||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using SqlSugar;
|
||||||
|
using System.Text.Json;
|
||||||
|
using YY.Admin.Core;
|
||||||
|
using YY.Admin.Core.Entity;
|
||||||
|
using YY.Admin.Services.Service.Category.Dto;
|
||||||
|
using YY.Admin.Services.Service.Jeecg;
|
||||||
|
|
||||||
|
namespace YY.Admin.Services.Service.Category;
|
||||||
|
|
||||||
|
public class JeecgCategorySyncService : IJeecgCategorySyncService, ISingletonDependency
|
||||||
|
{
|
||||||
|
private readonly ISqlSugarClient _dbContext;
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
private readonly IJeecgBackendGateway _jeecgGateway;
|
||||||
|
|
||||||
|
public JeecgCategorySyncService(
|
||||||
|
ISqlSugarClient dbContext,
|
||||||
|
IConfiguration configuration,
|
||||||
|
IJeecgBackendGateway jeecgGateway)
|
||||||
|
{
|
||||||
|
_dbContext = dbContext;
|
||||||
|
_configuration = configuration;
|
||||||
|
_jeecgGateway = jeecgGateway;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<SqlSugarPagedList<JeecgCategoryItemOutput>> PageAsync(PageJeecgCategoryItemInput input)
|
||||||
|
{
|
||||||
|
var name = input.Name;
|
||||||
|
var code = input.Code;
|
||||||
|
var pid = input.Pid;
|
||||||
|
var query = _dbContext.Queryable<JeecgSysCategoryItem>().ClearFilter()
|
||||||
|
.WhereIF(!string.IsNullOrWhiteSpace(name), x => x.Name != null && x.Name.Contains(name!))
|
||||||
|
.WhereIF(!string.IsNullOrWhiteSpace(code), x => x.Code != null && x.Code.Contains(code!))
|
||||||
|
.WhereIF(!string.IsNullOrWhiteSpace(pid), x => x.Pid == pid);
|
||||||
|
|
||||||
|
query = query.OrderBy(x => SqlFunc.IsNull(x.Code, ""))
|
||||||
|
.OrderBy(x => SqlFunc.IsNull(x.Name, ""))
|
||||||
|
.OrderBy(x => SqlFunc.Desc(x.UpdateTime));
|
||||||
|
|
||||||
|
RefAsync<int> total = 0;
|
||||||
|
var list = await query.ToPageListAsync(input.Page, input.PageSize, total);
|
||||||
|
var items = list.Select(x => new JeecgCategoryItemOutput
|
||||||
|
{
|
||||||
|
Id = x.Id,
|
||||||
|
Pid = x.Pid,
|
||||||
|
Name = x.Name,
|
||||||
|
Code = x.Code,
|
||||||
|
HasChild = x.HasChild,
|
||||||
|
CreateTime = x.CreateTime,
|
||||||
|
UpdateTime = x.UpdateTime
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
return new SqlSugarPagedList<JeecgCategoryItemOutput>
|
||||||
|
{
|
||||||
|
Page = input.Page,
|
||||||
|
PageSize = input.PageSize,
|
||||||
|
Total = total,
|
||||||
|
TotalPages = input.PageSize > 0 ? (int)Math.Ceiling(total / (double)input.PageSize) : 0,
|
||||||
|
HasNextPage = input.PageSize > 0 && input.Page < (int)Math.Ceiling(total / (double)input.PageSize),
|
||||||
|
HasPrevPage = input.Page > 1,
|
||||||
|
Items = items
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<int> SyncFromJeecgAsync()
|
||||||
|
{
|
||||||
|
var baseUrl = _configuration.GetValue<string>("JeecgIntegration:BaseUrl")?.TrimEnd('/');
|
||||||
|
if (string.IsNullOrWhiteSpace(baseUrl))
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
var queue = new Queue<string>();
|
||||||
|
var visited = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
queue.Enqueue("0");
|
||||||
|
visited.Add("0");
|
||||||
|
var synced = 0;
|
||||||
|
|
||||||
|
while (queue.Count > 0)
|
||||||
|
{
|
||||||
|
var pid = queue.Dequeue();
|
||||||
|
var requestUrl = $"{baseUrl}/sys/category/anon/childList?pid={Uri.EscapeDataString(pid)}";
|
||||||
|
var json = await _jeecgGateway.ExecuteGetStringAsync(requestUrl);
|
||||||
|
if (string.IsNullOrWhiteSpace(json))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var doc = JsonDocument.Parse(json);
|
||||||
|
var root = doc.RootElement;
|
||||||
|
if (!(root.TryGetProperty("success", out var successEl) && successEl.GetBoolean()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!root.TryGetProperty("result", out var listEl) || listEl.ValueKind != JsonValueKind.Array)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var row in listEl.EnumerateArray())
|
||||||
|
{
|
||||||
|
var id = GetString(row, "id");
|
||||||
|
if (string.IsNullOrWhiteSpace(id))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var existing = await _dbContext.Queryable<JeecgSysCategoryItem>()
|
||||||
|
.ClearFilter()
|
||||||
|
.Where(x => x.Id == id)
|
||||||
|
.FirstAsync();
|
||||||
|
|
||||||
|
if (existing == null)
|
||||||
|
{
|
||||||
|
existing = new JeecgSysCategoryItem { Id = id };
|
||||||
|
}
|
||||||
|
|
||||||
|
existing.Pid = GetString(row, "pid");
|
||||||
|
existing.Name = GetString(row, "name");
|
||||||
|
existing.Code = GetString(row, "code");
|
||||||
|
existing.HasChild = GetString(row, "hasChild");
|
||||||
|
existing.CreateBy = GetString(row, "createBy");
|
||||||
|
existing.CreateTime = GetDateTime(row, "createTime");
|
||||||
|
existing.UpdateBy = GetString(row, "updateBy");
|
||||||
|
existing.UpdateTime = GetDateTime(row, "updateTime");
|
||||||
|
|
||||||
|
var existsCount = await _dbContext.Queryable<JeecgSysCategoryItem>()
|
||||||
|
.ClearFilter()
|
||||||
|
.Where(x => x.Id == existing.Id)
|
||||||
|
.CountAsync();
|
||||||
|
if (existsCount > 0)
|
||||||
|
{
|
||||||
|
await _dbContext.Updateable(existing).ExecuteCommandAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await _dbContext.Insertable(existing).ExecuteCommandAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
synced++;
|
||||||
|
|
||||||
|
if (existing.HasChild == "1" && !visited.Contains(existing.Id))
|
||||||
|
{
|
||||||
|
queue.Enqueue(existing.Id);
|
||||||
|
visited.Add(existing.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return synced;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<JeecgCategoryTreeNodeDto>> LoadTreeAsync()
|
||||||
|
{
|
||||||
|
return await BuildLocalTreeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<List<JeecgCategoryTreeNodeDto>> BuildLocalTreeAsync()
|
||||||
|
{
|
||||||
|
var allItems = await _dbContext.Queryable<JeecgSysCategoryItem>()
|
||||||
|
.ClearFilter()
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
if (allItems == null || allItems.Count == 0)
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
var nodeMap = allItems
|
||||||
|
.Where(x => !string.IsNullOrWhiteSpace(x.Id))
|
||||||
|
.ToDictionary(
|
||||||
|
x => x.Id,
|
||||||
|
x => new JeecgCategoryTreeNodeDto
|
||||||
|
{
|
||||||
|
Id = x.Id,
|
||||||
|
Pid = x.Pid,
|
||||||
|
Name = x.Name,
|
||||||
|
Code = x.Code
|
||||||
|
},
|
||||||
|
StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
var roots = new List<JeecgCategoryTreeNodeDto>();
|
||||||
|
foreach (var node in nodeMap.Values)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(node.Pid) || node.Pid == "0" || !nodeMap.TryGetValue(node.Pid, out var parent))
|
||||||
|
{
|
||||||
|
roots.Add(node);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
parent.Children.Add(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
SortTreeNodes(roots);
|
||||||
|
return roots;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SortTreeNodes(List<JeecgCategoryTreeNodeDto> nodes)
|
||||||
|
{
|
||||||
|
nodes.Sort((a, b) =>
|
||||||
|
{
|
||||||
|
var codeCompare = string.Compare(a.Code, b.Code, StringComparison.OrdinalIgnoreCase);
|
||||||
|
return codeCompare != 0 ? codeCompare : string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase);
|
||||||
|
});
|
||||||
|
foreach (var node in nodes)
|
||||||
|
{
|
||||||
|
if (node.Children.Count > 0)
|
||||||
|
{
|
||||||
|
SortTreeNodes(node.Children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string? GetString(JsonElement row, string propertyName)
|
||||||
|
{
|
||||||
|
if (!row.TryGetProperty(propertyName, out var el))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (el.ValueKind == JsonValueKind.String)
|
||||||
|
{
|
||||||
|
return el.GetString();
|
||||||
|
}
|
||||||
|
return el.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static DateTime? GetDateTime(JsonElement row, string propertyName)
|
||||||
|
{
|
||||||
|
if (!row.TryGetProperty(propertyName, out var el))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (el.ValueKind == JsonValueKind.String && DateTime.TryParse(el.GetString(), out var dt))
|
||||||
|
{
|
||||||
|
return dt;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,215 @@
|
|||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Web;
|
||||||
|
using YY.Admin.Core;
|
||||||
|
using YY.Admin.Core.Entity;
|
||||||
|
using YY.Admin.Core.Services;
|
||||||
|
|
||||||
|
namespace YY.Admin.Services.Service.MixerMaterial;
|
||||||
|
|
||||||
|
public class MixerMaterialService : IMixerMaterialService, ISingletonDependency
|
||||||
|
{
|
||||||
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
|
private readonly IConfiguration _configuration;
|
||||||
|
private readonly ILoggerService _logger;
|
||||||
|
|
||||||
|
private static readonly JsonSerializerOptions _jsonOpts = new()
|
||||||
|
{
|
||||||
|
PropertyNameCaseInsensitive = true,
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||||
|
Converters = { new NullableDateTimeJsonConverter() }
|
||||||
|
};
|
||||||
|
|
||||||
|
public MixerMaterialService(
|
||||||
|
IHttpClientFactory httpClientFactory,
|
||||||
|
IConfiguration configuration,
|
||||||
|
ILoggerService logger)
|
||||||
|
{
|
||||||
|
_httpClientFactory = httpClientFactory;
|
||||||
|
_configuration = configuration;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string BaseUrl => (_configuration.GetValue<string>("JeecgIntegration:BaseUrl") ?? "http://localhost:8080/jeecg-boot").TrimEnd('/');
|
||||||
|
private HttpClient CreateClient() => _httpClientFactory.CreateClient("JeecgApi");
|
||||||
|
|
||||||
|
public async Task<MixerMaterialPageResult> PageAsync(
|
||||||
|
int pageNo,
|
||||||
|
int pageSize,
|
||||||
|
string? materialCode = null,
|
||||||
|
string? materialName = null,
|
||||||
|
string? erpCode = null,
|
||||||
|
string? majorCategoryId = null,
|
||||||
|
string? minorCategoryId = null,
|
||||||
|
CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var query = HttpUtility.ParseQueryString(string.Empty);
|
||||||
|
query["pageNo"] = pageNo.ToString();
|
||||||
|
query["pageSize"] = pageSize.ToString();
|
||||||
|
if (!string.IsNullOrWhiteSpace(materialCode)) query["materialCode"] = materialCode;
|
||||||
|
if (!string.IsNullOrWhiteSpace(materialName)) query["materialName"] = materialName;
|
||||||
|
if (!string.IsNullOrWhiteSpace(erpCode)) query["erpCode"] = erpCode;
|
||||||
|
if (!string.IsNullOrWhiteSpace(majorCategoryId)) query["majorCategoryId"] = majorCategoryId;
|
||||||
|
if (!string.IsNullOrWhiteSpace(minorCategoryId)) query["minorCategoryId"] = minorCategoryId;
|
||||||
|
|
||||||
|
var url = $"{BaseUrl}/mes/material/mixerMaterial/anon/list?{query}";
|
||||||
|
using var client = CreateClient();
|
||||||
|
var resp = await client.GetAsync(url, ct).ConfigureAwait(false);
|
||||||
|
resp.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
|
||||||
|
using var doc = JsonDocument.Parse(json);
|
||||||
|
var result = doc.RootElement.GetProperty("result");
|
||||||
|
var records = result.GetProperty("records").Deserialize<List<MesMixerMaterial>>(_jsonOpts) ?? new();
|
||||||
|
var total = result.TryGetProperty("total", out var totalEl) ? totalEl.GetInt64() : records.Count;
|
||||||
|
return new MixerMaterialPageResult(records, total, pageNo, pageSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<MesMixerMaterial?> GetByIdAsync(string id, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var url = $"{BaseUrl}/mes/material/mixerMaterial/anon/queryById?id={Uri.EscapeDataString(id)}";
|
||||||
|
using var client = CreateClient();
|
||||||
|
var resp = await client.GetAsync(url, ct).ConfigureAwait(false);
|
||||||
|
if (!resp.IsSuccessStatusCode) return null;
|
||||||
|
|
||||||
|
var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
|
||||||
|
using var doc = JsonDocument.Parse(json);
|
||||||
|
if (!doc.RootElement.TryGetProperty("result", out var resultEl)) return null;
|
||||||
|
return resultEl.Deserialize<MesMixerMaterial>(_jsonOpts);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<bool> AddAsync(MesMixerMaterial material, CancellationToken ct = default)
|
||||||
|
=> PostJsonAsync($"{BaseUrl}/mes/material/mixerMaterial/anon/add", material, ct);
|
||||||
|
|
||||||
|
public Task<bool> EditAsync(MesMixerMaterial material, CancellationToken ct = default)
|
||||||
|
=> PostJsonAsync($"{BaseUrl}/mes/material/mixerMaterial/anon/edit", material, ct);
|
||||||
|
|
||||||
|
public async Task<bool> DeleteAsync(string id, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var url = $"{BaseUrl}/mes/material/mixerMaterial/anon/delete?id={Uri.EscapeDataString(id)}";
|
||||||
|
using var client = CreateClient();
|
||||||
|
var resp = await client.DeleteAsync(url, ct).ConfigureAwait(false);
|
||||||
|
return resp.IsSuccessStatusCode && await IsSuccessResultAsync(resp, ct).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> DeleteBatchAsync(string ids, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var url = $"{BaseUrl}/mes/material/mixerMaterial/anon/deleteBatch?ids={Uri.EscapeDataString(ids)}";
|
||||||
|
using var client = CreateClient();
|
||||||
|
var resp = await client.DeleteAsync(url, ct).ConfigureAwait(false);
|
||||||
|
return resp.IsSuccessStatusCode && await IsSuccessResultAsync(resp, ct).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<KeyValuePair<string, string>>> GetMajorCategoryOptionsAsync(CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
var url = $"{BaseUrl}/sys/category/anon/loadTreeData?pcode=XSLMES_MATERIAL";
|
||||||
|
using var client = CreateClient();
|
||||||
|
var resp = await client.GetAsync(url, ct).ConfigureAwait(false);
|
||||||
|
if (!resp.IsSuccessStatusCode) return [];
|
||||||
|
var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
|
||||||
|
using var doc = JsonDocument.Parse(json);
|
||||||
|
var arr = doc.RootElement.TryGetProperty("result", out var resultEl) ? resultEl : doc.RootElement;
|
||||||
|
return ParseTreeOptions(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<List<KeyValuePair<string, string>>> GetMinorCategoryOptionsAsync(string majorCategoryId, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(majorCategoryId)) return [];
|
||||||
|
var url = $"{BaseUrl}/sys/category/anon/loadTreeData?pid={Uri.EscapeDataString(majorCategoryId)}";
|
||||||
|
using var client = CreateClient();
|
||||||
|
var resp = await client.GetAsync(url, ct).ConfigureAwait(false);
|
||||||
|
if (!resp.IsSuccessStatusCode) return [];
|
||||||
|
var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
|
||||||
|
using var doc = JsonDocument.Parse(json);
|
||||||
|
var arr = doc.RootElement.TryGetProperty("result", out var resultEl) ? resultEl : doc.RootElement;
|
||||||
|
return ParseTreeOptions(arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<KeyValuePair<string, string>> ParseTreeOptions(JsonElement root)
|
||||||
|
{
|
||||||
|
var list = new List<KeyValuePair<string, string>>();
|
||||||
|
if (root.ValueKind != JsonValueKind.Array) return list;
|
||||||
|
foreach (var item in root.EnumerateArray())
|
||||||
|
{
|
||||||
|
var text = item.TryGetProperty("title", out var titleEl) ? titleEl.GetString() : null;
|
||||||
|
var key = item.TryGetProperty("key", out var keyEl) ? keyEl.GetString() : null;
|
||||||
|
if (!string.IsNullOrWhiteSpace(text) && !string.IsNullOrWhiteSpace(key))
|
||||||
|
{
|
||||||
|
list.Add(new KeyValuePair<string, string>(text!, key!));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<bool> PostJsonAsync(string url, object body, CancellationToken ct)
|
||||||
|
{
|
||||||
|
var content = new StringContent(JsonSerializer.Serialize(body, _jsonOpts), Encoding.UTF8, "application/json");
|
||||||
|
using var client = CreateClient();
|
||||||
|
var resp = await client.PostAsync(url, content, ct).ConfigureAwait(false);
|
||||||
|
return resp.IsSuccessStatusCode && await IsSuccessResultAsync(resp, ct).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<bool> IsSuccessResultAsync(HttpResponseMessage resp, CancellationToken ct)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var json = await resp.Content.ReadAsStringAsync(ct).ConfigureAwait(false);
|
||||||
|
using var doc = JsonDocument.Parse(json);
|
||||||
|
if (doc.RootElement.TryGetProperty("code", out var code))
|
||||||
|
{
|
||||||
|
return code.GetInt32() == 200;
|
||||||
|
}
|
||||||
|
if (doc.RootElement.TryGetProperty("success", out var success))
|
||||||
|
{
|
||||||
|
return success.GetBoolean();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class NullableDateTimeJsonConverter : JsonConverter<DateTime?>
|
||||||
|
{
|
||||||
|
private static readonly string[] SupportedFormats =
|
||||||
|
[
|
||||||
|
"yyyy-MM-dd HH:mm:ss",
|
||||||
|
"yyyy-MM-dd HH:mm:ss.fff",
|
||||||
|
"yyyy-MM-ddTHH:mm:ss",
|
||||||
|
"yyyy-MM-ddTHH:mm:ss.fff",
|
||||||
|
"yyyy-MM-ddTHH:mm:ssZ",
|
||||||
|
"yyyy-MM-ddTHH:mm:ss.fffZ"
|
||||||
|
];
|
||||||
|
|
||||||
|
public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
if (reader.TokenType == JsonTokenType.Null) return null;
|
||||||
|
if (reader.TokenType == JsonTokenType.String)
|
||||||
|
{
|
||||||
|
var raw = reader.GetString();
|
||||||
|
if (string.IsNullOrWhiteSpace(raw)) return null;
|
||||||
|
if (DateTime.TryParseExact(raw, SupportedFormats, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.AssumeLocal, out var exact))
|
||||||
|
{
|
||||||
|
return exact;
|
||||||
|
}
|
||||||
|
if (DateTime.TryParse(raw, out var fallback))
|
||||||
|
{
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new JsonException($"无法将 JSON 值转换为 DateTime?,token={reader.TokenType}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options)
|
||||||
|
{
|
||||||
|
if (value.HasValue) writer.WriteStringValue(value.Value.ToString("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
else writer.WriteNullValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
using Prism.Events;
|
||||||
|
using System.Text.Json;
|
||||||
|
using YY.Admin.Core;
|
||||||
|
using YY.Admin.Core.Events;
|
||||||
|
using YY.Admin.Core.Services;
|
||||||
|
|
||||||
|
namespace YY.Admin.Services.Service.MixerMaterial;
|
||||||
|
|
||||||
|
public class MixerMaterialSyncCoordinator : ISingletonDependency
|
||||||
|
{
|
||||||
|
private readonly IEventAggregator _eventAggregator;
|
||||||
|
private readonly ILoggerService _logger;
|
||||||
|
|
||||||
|
public MixerMaterialSyncCoordinator(IEventAggregator eventAggregator, ILoggerService logger)
|
||||||
|
{
|
||||||
|
_eventAggregator = eventAggregator;
|
||||||
|
_logger = logger;
|
||||||
|
_eventAggregator.GetEvent<RemoteCommandReceivedEvent>()
|
||||||
|
.Subscribe(OnRemoteCommand, ThreadOption.BackgroundThread);
|
||||||
|
_eventAggregator.GetEvent<NetworkStatusChangedEvent>()
|
||||||
|
.Subscribe(OnNetworkStatusChanged, ThreadOption.BackgroundThread);
|
||||||
|
_logger.Information("[密炼物料推送] MixerMaterialSyncCoordinator 已启动");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnNetworkStatusChanged(NetworkStatusChangedPayload payload)
|
||||||
|
{
|
||||||
|
if (!payload.IsOnline) return;
|
||||||
|
_eventAggregator.GetEvent<MixerMaterialChangedEvent>()
|
||||||
|
.Publish(new MixerMaterialChangedPayload { Action = "reconnect" });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRemoteCommand(RemoteCommandPayload payload)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var json = payload.CommandJson ?? string.Empty;
|
||||||
|
if (string.IsNullOrWhiteSpace(json)) return;
|
||||||
|
|
||||||
|
using var doc = JsonDocument.Parse(json);
|
||||||
|
if (!doc.RootElement.TryGetProperty("cmd", out var cmdEl)) return;
|
||||||
|
if (!cmdEl.GetString().Equals("MIXER_MATERIAL_CHANGED", StringComparison.OrdinalIgnoreCase)) return;
|
||||||
|
|
||||||
|
doc.RootElement.TryGetProperty("action", out var actionEl);
|
||||||
|
doc.RootElement.TryGetProperty("mixerMaterialId", out var idEl);
|
||||||
|
if (idEl.ValueKind != JsonValueKind.String && doc.RootElement.TryGetProperty("id", out var id2El))
|
||||||
|
{
|
||||||
|
idEl = id2El;
|
||||||
|
}
|
||||||
|
|
||||||
|
var changed = new MixerMaterialChangedPayload
|
||||||
|
{
|
||||||
|
Action = actionEl.GetString() ?? string.Empty,
|
||||||
|
MixerMaterialId = idEl.ValueKind == JsonValueKind.String ? idEl.GetString() : null
|
||||||
|
};
|
||||||
|
_eventAggregator.GetEvent<MixerMaterialChangedEvent>().Publish(changed);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Warning($"[密炼物料推送] 处理STOMP命令失败:{ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -138,6 +138,10 @@ public class StompWebSocketService : ISignalRService
|
|||||||
await SendFrameAsync(
|
await SendFrameAsync(
|
||||||
BuildSubscribeFrame("sub-mes-weight-records", "/topic/sync/mes-weight-records"),
|
BuildSubscribeFrame("sub-mes-weight-records", "/topic/sync/mes-weight-records"),
|
||||||
cancellationToken).ConfigureAwait(false);
|
cancellationToken).ConfigureAwait(false);
|
||||||
|
// 密炼物料数据变更:订阅 /topic/sync/mes-mixer-materials
|
||||||
|
await SendFrameAsync(
|
||||||
|
BuildSubscribeFrame("sub-mes-mixer-material", "/topic/sync/mes-mixer-materials"),
|
||||||
|
cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
// 订阅服务端 PONG 回复(应用层假在线检测)
|
// 订阅服务端 PONG 回复(应用层假在线检测)
|
||||||
await SendFrameAsync(
|
await SendFrameAsync(
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ using YY.Admin.Views.Dialogs;
|
|||||||
using YY.Admin.Views.SysManage;
|
using YY.Admin.Views.SysManage;
|
||||||
using YY.Admin.Views.Customer;
|
using YY.Admin.Views.Customer;
|
||||||
using YY.Admin.Views.Supplier;
|
using YY.Admin.Views.Supplier;
|
||||||
|
using YY.Admin.Views.MixerMaterial;
|
||||||
using YY.Admin.ViewModels.Vehicle;
|
using YY.Admin.ViewModels.Vehicle;
|
||||||
using YY.Admin.Views.Vehicle;
|
using YY.Admin.Views.Vehicle;
|
||||||
using YY.Admin.Views.WeightRecord;
|
using YY.Admin.Views.WeightRecord;
|
||||||
@@ -52,6 +53,7 @@ namespace YY.Admin
|
|||||||
containerRegistry.RegisterForNavigation<MenuTreeView>();
|
containerRegistry.RegisterForNavigation<MenuTreeView>();
|
||||||
containerRegistry.RegisterForNavigation<UserManagementView>();
|
containerRegistry.RegisterForNavigation<UserManagementView>();
|
||||||
containerRegistry.RegisterForNavigation<DataDictionaryManagementView>();
|
containerRegistry.RegisterForNavigation<DataDictionaryManagementView>();
|
||||||
|
containerRegistry.RegisterForNavigation<CategoryDictionaryManagementView>();
|
||||||
containerRegistry.RegisterForNavigation<RoleManagementView>();
|
containerRegistry.RegisterForNavigation<RoleManagementView>();
|
||||||
containerRegistry.RegisterForNavigation<TenantManagementView>();
|
containerRegistry.RegisterForNavigation<TenantManagementView>();
|
||||||
containerRegistry.RegisterForNavigation<MenuManagementView>();
|
containerRegistry.RegisterForNavigation<MenuManagementView>();
|
||||||
@@ -66,6 +68,8 @@ namespace YY.Admin
|
|||||||
containerRegistry.RegisterForNavigation<WeightRecordListView>();
|
containerRegistry.RegisterForNavigation<WeightRecordListView>();
|
||||||
// 地磅称重操作(大页面操作台)
|
// 地磅称重操作(大页面操作台)
|
||||||
containerRegistry.RegisterForNavigation<WeightRecordOperationView>();
|
containerRegistry.RegisterForNavigation<WeightRecordOperationView>();
|
||||||
|
// 密炼物料信息
|
||||||
|
containerRegistry.RegisterForNavigation<MixerMaterialListView>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public class DialogWindow : Window, IDialogWindow
|
public class DialogWindow : Window, IDialogWindow
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ using YY.Admin.Infrastructure.Storage;
|
|||||||
using YY.Admin.Infrastructure.Sync;
|
using YY.Admin.Infrastructure.Sync;
|
||||||
using YY.Admin.Services.Service.Customer;
|
using YY.Admin.Services.Service.Customer;
|
||||||
using YY.Admin.Services.Service.Supplier;
|
using YY.Admin.Services.Service.Supplier;
|
||||||
|
using YY.Admin.Services.Service.MixerMaterial;
|
||||||
using YY.Admin.Services.Service.Vehicle;
|
using YY.Admin.Services.Service.Vehicle;
|
||||||
using YY.Admin.Services.Service.WeightRecord;
|
using YY.Admin.Services.Service.WeightRecord;
|
||||||
|
|
||||||
@@ -46,6 +47,9 @@ public class SyncModule : IModule
|
|||||||
// 磅单管理:免密 API 直连 + STOMP 实时通知
|
// 磅单管理:免密 API 直连 + STOMP 实时通知
|
||||||
containerRegistry.RegisterSingleton<IWeightRecordService, WeightRecordService>();
|
containerRegistry.RegisterSingleton<IWeightRecordService, WeightRecordService>();
|
||||||
containerRegistry.RegisterSingleton<WeightRecordSyncCoordinator>();
|
containerRegistry.RegisterSingleton<WeightRecordSyncCoordinator>();
|
||||||
|
// 密炼物料信息:API直连 + STOMP实时通知
|
||||||
|
containerRegistry.RegisterSingleton<IMixerMaterialService, MixerMaterialService>();
|
||||||
|
containerRegistry.RegisterSingleton<MixerMaterialSyncCoordinator>();
|
||||||
|
|
||||||
var serviceCollection = new ServiceCollection();
|
var serviceCollection = new ServiceCollection();
|
||||||
serviceCollection.AddTransient<DisconnectGuardHandler>();
|
serviceCollection.AddTransient<DisconnectGuardHandler>();
|
||||||
@@ -98,6 +102,8 @@ public class SyncModule : IModule
|
|||||||
_ = containerProvider.Resolve<SupplierSyncCoordinator>();
|
_ = containerProvider.Resolve<SupplierSyncCoordinator>();
|
||||||
// 强制实例化磅单同步协调器
|
// 强制实例化磅单同步协调器
|
||||||
_ = containerProvider.Resolve<WeightRecordSyncCoordinator>();
|
_ = containerProvider.Resolve<WeightRecordSyncCoordinator>();
|
||||||
|
// 强制实例化密炼物料同步协调器
|
||||||
|
_ = containerProvider.Resolve<MixerMaterialSyncCoordinator>();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
|
private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
|
||||||
|
|||||||
@@ -54,6 +54,13 @@ namespace YY.Admin.ViewModels.Control
|
|||||||
["/platform/dict"] = "DataDictionaryManagementView",
|
["/platform/dict"] = "DataDictionaryManagementView",
|
||||||
["sysDict"] = "DataDictionaryManagementView",
|
["sysDict"] = "DataDictionaryManagementView",
|
||||||
|
|
||||||
|
// 已实现页面:分类字典
|
||||||
|
["CategoryDictionaryManagementView"] = "CategoryDictionaryManagementView",
|
||||||
|
["/system/category"] = "CategoryDictionaryManagementView",
|
||||||
|
["/system/category/index"] = "CategoryDictionaryManagementView",
|
||||||
|
["/platform/category"] = "CategoryDictionaryManagementView",
|
||||||
|
["sysCategory"] = "CategoryDictionaryManagementView",
|
||||||
|
|
||||||
// 已实现页面:角色管理
|
// 已实现页面:角色管理
|
||||||
["RoleManagementView"] = "RoleManagementView",
|
["RoleManagementView"] = "RoleManagementView",
|
||||||
["/system/role"] = "RoleManagementView",
|
["/system/role"] = "RoleManagementView",
|
||||||
@@ -108,7 +115,12 @@ namespace YY.Admin.ViewModels.Control
|
|||||||
// 已实现页面:地磅称重操作
|
// 已实现页面:地磅称重操作
|
||||||
["WeightRecordOperationView"] = "WeightRecordOperationView",
|
["WeightRecordOperationView"] = "WeightRecordOperationView",
|
||||||
["/xslmes/weightRecordOperation"] = "WeightRecordOperationView",
|
["/xslmes/weightRecordOperation"] = "WeightRecordOperationView",
|
||||||
["weightRecordOperation"] = "WeightRecordOperationView"
|
["weightRecordOperation"] = "WeightRecordOperationView",
|
||||||
|
|
||||||
|
// 已实现页面:密炼物料信息
|
||||||
|
["MixerMaterialListView"] = "MixerMaterialListView",
|
||||||
|
["/xslmes/mesMixerMaterial"] = "MixerMaterialListView",
|
||||||
|
["mesMixerMaterial"] = "MixerMaterialListView"
|
||||||
};
|
};
|
||||||
|
|
||||||
private MenuItem? _selectedMenuItem;
|
private MenuItem? _selectedMenuItem;
|
||||||
|
|||||||
@@ -0,0 +1,186 @@
|
|||||||
|
using HandyControl.Controls;
|
||||||
|
using HandyControl.Tools.Extension;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using YY.Admin.Core;
|
||||||
|
using YY.Admin.Core.Entity;
|
||||||
|
using YY.Admin.Core.Services;
|
||||||
|
|
||||||
|
namespace YY.Admin.ViewModels.MixerMaterial;
|
||||||
|
|
||||||
|
public class MixerMaterialEditDialogViewModel : BaseViewModel, IDialogResultable<bool>
|
||||||
|
{
|
||||||
|
private readonly IMixerMaterialService _mixerMaterialService;
|
||||||
|
|
||||||
|
private MesMixerMaterial? _material;
|
||||||
|
public MesMixerMaterial? Material
|
||||||
|
{
|
||||||
|
get => _material;
|
||||||
|
set => SetProperty(ref _material, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsAddMode => string.IsNullOrWhiteSpace(Material?.Id);
|
||||||
|
public string DialogTitle => IsAddMode ? "新增密炼物料" : "编辑密炼物料";
|
||||||
|
|
||||||
|
public ObservableCollection<KeyValuePair<string, string>> MajorCategoryOptions { get; } = new();
|
||||||
|
public ObservableCollection<KeyValuePair<string, string>> MinorCategoryOptions { get; } = new();
|
||||||
|
public ObservableCollection<KeyValuePair<string, int>> FeedManageStatusOptions { get; } =
|
||||||
|
[
|
||||||
|
new("在投管", 1),
|
||||||
|
new("未投管", 0)
|
||||||
|
];
|
||||||
|
public ObservableCollection<KeyValuePair<string, int>> UseStatusOptions { get; } =
|
||||||
|
[
|
||||||
|
new("使用中", 1),
|
||||||
|
new("停用", 0)
|
||||||
|
];
|
||||||
|
|
||||||
|
private bool _result;
|
||||||
|
public bool Result { get => _result; set => SetProperty(ref _result, value); }
|
||||||
|
public Action? CloseAction { get; set; }
|
||||||
|
|
||||||
|
public DelegateCommand SaveCommand { get; }
|
||||||
|
public DelegateCommand CancelCommand { get; }
|
||||||
|
public DelegateCommand MajorCategoryChangedCommand { get; }
|
||||||
|
|
||||||
|
public MixerMaterialEditDialogViewModel(
|
||||||
|
IMixerMaterialService mixerMaterialService,
|
||||||
|
IContainerExtension container,
|
||||||
|
IRegionManager regionManager) : base(container, regionManager)
|
||||||
|
{
|
||||||
|
_mixerMaterialService = mixerMaterialService;
|
||||||
|
SaveCommand = new DelegateCommand(async () => await SaveAsync());
|
||||||
|
CancelCommand = new DelegateCommand(() => CloseAction?.Invoke());
|
||||||
|
MajorCategoryChangedCommand = new DelegateCommand(async () => await OnMajorCategoryChangedAsync());
|
||||||
|
_ = LoadMajorCategoryOptionsAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitializeForAdd()
|
||||||
|
{
|
||||||
|
Material = new MesMixerMaterial
|
||||||
|
{
|
||||||
|
FeedManageStatus = 1,
|
||||||
|
UseStatus = 1
|
||||||
|
};
|
||||||
|
MinorCategoryOptions.Clear();
|
||||||
|
RaisePropertyChanged(nameof(IsAddMode));
|
||||||
|
RaisePropertyChanged(nameof(DialogTitle));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void InitializeForEdit(MesMixerMaterial material)
|
||||||
|
{
|
||||||
|
Material = new MesMixerMaterial
|
||||||
|
{
|
||||||
|
Id = material.Id,
|
||||||
|
MaterialCode = material.MaterialCode,
|
||||||
|
MaterialName = material.MaterialName,
|
||||||
|
ErpCode = material.ErpCode,
|
||||||
|
MajorCategoryId = material.MajorCategoryId,
|
||||||
|
MinorCategoryId = material.MinorCategoryId,
|
||||||
|
MaterialDesc = material.MaterialDesc,
|
||||||
|
AliasName = material.AliasName,
|
||||||
|
FeedManageStatus = material.FeedManageStatus,
|
||||||
|
UseStatus = material.UseStatus,
|
||||||
|
SpecificGravity = material.SpecificGravity,
|
||||||
|
ShelfLifeDays = material.ShelfLifeDays,
|
||||||
|
MinBakeMinutes = material.MinBakeMinutes,
|
||||||
|
TotalSafetyStockKg = material.TotalSafetyStockKg,
|
||||||
|
QualifiedSafetyStockKg = material.QualifiedSafetyStockKg,
|
||||||
|
Remark = material.Remark,
|
||||||
|
TenantId = material.TenantId,
|
||||||
|
};
|
||||||
|
_ = LoadMinorCategoryOptionsAsync(Material.MajorCategoryId);
|
||||||
|
RaisePropertyChanged(nameof(IsAddMode));
|
||||||
|
RaisePropertyChanged(nameof(DialogTitle));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadMajorCategoryOptionsAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MajorCategoryOptions.Clear();
|
||||||
|
var options = await _mixerMaterialService.GetMajorCategoryOptionsAsync();
|
||||||
|
foreach (var item in options)
|
||||||
|
{
|
||||||
|
MajorCategoryOptions.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadMinorCategoryOptionsAsync(string? majorCategoryId)
|
||||||
|
{
|
||||||
|
MinorCategoryOptions.Clear();
|
||||||
|
if (string.IsNullOrWhiteSpace(majorCategoryId))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var options = await _mixerMaterialService.GetMinorCategoryOptionsAsync(majorCategoryId);
|
||||||
|
foreach (var item in options)
|
||||||
|
{
|
||||||
|
MinorCategoryOptions.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnMajorCategoryChangedAsync()
|
||||||
|
{
|
||||||
|
if (Material == null) return;
|
||||||
|
Material.MinorCategoryId = null;
|
||||||
|
RaisePropertyChanged(nameof(Material));
|
||||||
|
await LoadMinorCategoryOptionsAsync(Material.MajorCategoryId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SaveAsync()
|
||||||
|
{
|
||||||
|
if (Material == null) return;
|
||||||
|
if (string.IsNullOrWhiteSpace(Material.MaterialCode))
|
||||||
|
{
|
||||||
|
HandyControl.Controls.MessageBox.Warning("物料编码不能为空!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(Material.MaterialName))
|
||||||
|
{
|
||||||
|
HandyControl.Controls.MessageBox.Warning("物料名称不能为空!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(Material.MajorCategoryId))
|
||||||
|
{
|
||||||
|
HandyControl.Controls.MessageBox.Warning("物料大类不能为空!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(Material.MinorCategoryId))
|
||||||
|
{
|
||||||
|
HandyControl.Controls.MessageBox.Warning("物料小类不能为空!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
bool ok = IsAddMode
|
||||||
|
? await _mixerMaterialService.AddAsync(Material)
|
||||||
|
: await _mixerMaterialService.EditAsync(Material);
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
HandyControl.Controls.MessageBox.Error($"{(IsAddMode ? "新增" : "编辑")}密炼物料失败!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Result = true;
|
||||||
|
CloseAction?.Invoke();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
HandyControl.Controls.MessageBox.Error($"操作失败:{ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
using HandyControl.Controls;
|
||||||
|
using HandyControl.Tools.Extension;
|
||||||
|
using Prism.Events;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Windows;
|
||||||
|
using YY.Admin.Core;
|
||||||
|
using YY.Admin.Core.Entity;
|
||||||
|
using YY.Admin.Core.Events;
|
||||||
|
using YY.Admin.Core.Helper;
|
||||||
|
using YY.Admin.Core.Services;
|
||||||
|
using YY.Admin.Views.MixerMaterial;
|
||||||
|
|
||||||
|
namespace YY.Admin.ViewModels.MixerMaterial;
|
||||||
|
|
||||||
|
public class MixerMaterialListViewModel : BaseViewModel
|
||||||
|
{
|
||||||
|
private readonly IMixerMaterialService _mixerMaterialService;
|
||||||
|
private SubscriptionToken? _materialChangedToken;
|
||||||
|
|
||||||
|
private ObservableCollection<MesMixerMaterial> _materials = new();
|
||||||
|
public ObservableCollection<MesMixerMaterial> Materials
|
||||||
|
{
|
||||||
|
get => _materials;
|
||||||
|
set => SetProperty(ref _materials, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long _total;
|
||||||
|
public long Total { get => _total; set => SetProperty(ref _total, value); }
|
||||||
|
|
||||||
|
private int _pageNo = 1;
|
||||||
|
public int PageNo { get => _pageNo; set => SetProperty(ref _pageNo, value); }
|
||||||
|
|
||||||
|
private int _pageSize = 20;
|
||||||
|
public int PageSize { get => _pageSize; set => SetProperty(ref _pageSize, value); }
|
||||||
|
|
||||||
|
private string? _filterMaterialCode;
|
||||||
|
public string? FilterMaterialCode { get => _filterMaterialCode; set => SetProperty(ref _filterMaterialCode, value); }
|
||||||
|
|
||||||
|
private string? _filterMaterialName;
|
||||||
|
public string? FilterMaterialName { get => _filterMaterialName; set => SetProperty(ref _filterMaterialName, value); }
|
||||||
|
|
||||||
|
private string? _filterErpCode;
|
||||||
|
public string? FilterErpCode { get => _filterErpCode; set => SetProperty(ref _filterErpCode, value); }
|
||||||
|
|
||||||
|
private string? _filterMajorCategoryId;
|
||||||
|
public string? FilterMajorCategoryId
|
||||||
|
{
|
||||||
|
get => _filterMajorCategoryId;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _filterMajorCategoryId, value))
|
||||||
|
{
|
||||||
|
_ = OnMajorCategoryChangedAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string? _filterMinorCategoryId;
|
||||||
|
public string? FilterMinorCategoryId { get => _filterMinorCategoryId; set => SetProperty(ref _filterMinorCategoryId, value); }
|
||||||
|
|
||||||
|
public ObservableCollection<KeyValuePair<string, string>> MajorCategoryOptions { get; } = new();
|
||||||
|
public ObservableCollection<KeyValuePair<string, string>> MinorCategoryOptions { get; } = new();
|
||||||
|
|
||||||
|
public DelegateCommand SearchCommand { get; }
|
||||||
|
public DelegateCommand ResetCommand { get; }
|
||||||
|
public DelegateCommand AddCommand { get; }
|
||||||
|
public DelegateCommand<MesMixerMaterial> EditCommand { get; }
|
||||||
|
public DelegateCommand<MesMixerMaterial> DeleteCommand { get; }
|
||||||
|
public DelegateCommand PrevPageCommand { get; }
|
||||||
|
public DelegateCommand NextPageCommand { get; }
|
||||||
|
|
||||||
|
public MixerMaterialListViewModel(
|
||||||
|
IMixerMaterialService mixerMaterialService,
|
||||||
|
IContainerExtension container,
|
||||||
|
IRegionManager regionManager) : base(container, regionManager)
|
||||||
|
{
|
||||||
|
_mixerMaterialService = mixerMaterialService;
|
||||||
|
|
||||||
|
SearchCommand = new DelegateCommand(async () => { PageNo = 1; await LoadAsync(); });
|
||||||
|
ResetCommand = new DelegateCommand(async () =>
|
||||||
|
{
|
||||||
|
FilterMaterialCode = null;
|
||||||
|
FilterMaterialName = null;
|
||||||
|
FilterErpCode = null;
|
||||||
|
FilterMajorCategoryId = null;
|
||||||
|
FilterMinorCategoryId = null;
|
||||||
|
PageNo = 1;
|
||||||
|
await LoadMinorCategoryOptionsAsync();
|
||||||
|
await LoadAsync();
|
||||||
|
});
|
||||||
|
AddCommand = new DelegateCommand(async () => await ShowAddDialogAsync());
|
||||||
|
EditCommand = new DelegateCommand<MesMixerMaterial>(async m => await ShowEditDialogAsync(m));
|
||||||
|
DeleteCommand = new DelegateCommand<MesMixerMaterial>(async m => await DeleteAsync(m));
|
||||||
|
PrevPageCommand = new DelegateCommand(async () => { if (PageNo > 1) { PageNo--; await LoadAsync(); } });
|
||||||
|
NextPageCommand = new DelegateCommand(async () => { if ((long)PageNo * PageSize < Total) { PageNo++; await LoadAsync(); } });
|
||||||
|
|
||||||
|
_materialChangedToken = _eventAggregator
|
||||||
|
.GetEvent<MixerMaterialChangedEvent>()
|
||||||
|
.Subscribe(async _ => await LoadAsync(), ThreadOption.UIThread);
|
||||||
|
|
||||||
|
_ = InitializeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await LoadMajorCategoryOptionsAsync();
|
||||||
|
await LoadMinorCategoryOptionsAsync();
|
||||||
|
await UIHelper.WaitForRenderAsync();
|
||||||
|
await LoadAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.WriteLine($"密炼物料列表初始化失败: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadMajorCategoryOptionsAsync()
|
||||||
|
{
|
||||||
|
MajorCategoryOptions.Clear();
|
||||||
|
var options = await _mixerMaterialService.GetMajorCategoryOptionsAsync();
|
||||||
|
MajorCategoryOptions.Add(new KeyValuePair<string, string>("全部", ""));
|
||||||
|
foreach (var item in options)
|
||||||
|
{
|
||||||
|
MajorCategoryOptions.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadMinorCategoryOptionsAsync()
|
||||||
|
{
|
||||||
|
MinorCategoryOptions.Clear();
|
||||||
|
MinorCategoryOptions.Add(new KeyValuePair<string, string>("全部", ""));
|
||||||
|
if (string.IsNullOrWhiteSpace(FilterMajorCategoryId))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var options = await _mixerMaterialService.GetMinorCategoryOptionsAsync(FilterMajorCategoryId!);
|
||||||
|
foreach (var item in options)
|
||||||
|
{
|
||||||
|
MinorCategoryOptions.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task OnMajorCategoryChangedAsync()
|
||||||
|
{
|
||||||
|
FilterMinorCategoryId = null;
|
||||||
|
await LoadMinorCategoryOptionsAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LoadAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IsLoading = true;
|
||||||
|
var result = await _mixerMaterialService.PageAsync(
|
||||||
|
PageNo, PageSize, FilterMaterialCode, FilterMaterialName, FilterErpCode, FilterMajorCategoryId, FilterMinorCategoryId);
|
||||||
|
Materials = new ObservableCollection<MesMixerMaterial>(result.Records);
|
||||||
|
Total = result.Total;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Growl.Error($"加载密炼物料列表失败:{ex.Message}");
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsLoading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ShowAddDialogAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await HandyControl.Controls.Dialog.Show<MixerMaterialEditDialogView>()
|
||||||
|
.Initialize<MixerMaterialEditDialogViewModel>(vm => vm.InitializeForAdd())
|
||||||
|
.GetResultAsync<bool>();
|
||||||
|
if (result) await LoadAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Growl.Error($"打开新增对话框失败:{ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ShowEditDialogAsync(MesMixerMaterial material)
|
||||||
|
{
|
||||||
|
if (material == null) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var result = await HandyControl.Controls.Dialog.Show<MixerMaterialEditDialogView>()
|
||||||
|
.Initialize<MixerMaterialEditDialogViewModel>(vm => vm.InitializeForEdit(material))
|
||||||
|
.GetResultAsync<bool>();
|
||||||
|
if (result) await LoadAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Growl.Error($"打开编辑对话框失败:{ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task DeleteAsync(MesMixerMaterial material)
|
||||||
|
{
|
||||||
|
if (material?.Id == null) return;
|
||||||
|
var confirm = System.Windows.MessageBox.Show($"确定删除物料 {material.MaterialName}?此操作不可恢复!", "确认删除",
|
||||||
|
MessageBoxButton.OKCancel, MessageBoxImage.Question);
|
||||||
|
if (confirm != System.Windows.MessageBoxResult.OK) return;
|
||||||
|
|
||||||
|
var ok = await _mixerMaterialService.DeleteAsync(material.Id);
|
||||||
|
if (ok)
|
||||||
|
{
|
||||||
|
Growl.Success("删除成功!");
|
||||||
|
await LoadAsync();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Growl.Error("删除失败!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void CleanUp()
|
||||||
|
{
|
||||||
|
base.CleanUp();
|
||||||
|
if (_materialChangedToken != null)
|
||||||
|
{
|
||||||
|
_eventAggregator.GetEvent<MixerMaterialChangedEvent>().Unsubscribe(_materialChangedToken);
|
||||||
|
_materialChangedToken = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,143 @@
|
|||||||
|
using HandyControl.Controls;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using YY.Admin.Core;
|
||||||
|
using YY.Admin.Core.Helper;
|
||||||
|
using YY.Admin.Services.Service.Category;
|
||||||
|
using YY.Admin.Services.Service.Category.Dto;
|
||||||
|
using YY.Admin.ViewModels.Control;
|
||||||
|
|
||||||
|
namespace YY.Admin.ViewModels.SysManage;
|
||||||
|
|
||||||
|
public class CategoryDictionaryManagementViewModel : BaseViewModel
|
||||||
|
{
|
||||||
|
private readonly IJeecgCategorySyncService _categorySyncService;
|
||||||
|
|
||||||
|
private PaginationDataGridViewModel<JeecgCategoryItemOutput> _paginationDataGridViewModel;
|
||||||
|
public PaginationDataGridViewModel<JeecgCategoryItemOutput> PaginationDataGridViewModel
|
||||||
|
{
|
||||||
|
get => _paginationDataGridViewModel;
|
||||||
|
set => SetProperty(ref _paginationDataGridViewModel, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PageJeecgCategoryItemInput _input;
|
||||||
|
public PageJeecgCategoryItemInput Input
|
||||||
|
{
|
||||||
|
get => _input;
|
||||||
|
set => SetProperty(ref _input, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DelegateCommand SearchCommand { get; }
|
||||||
|
public DelegateCommand ResetCommand { get; }
|
||||||
|
public DelegateCommand SyncCommand { get; }
|
||||||
|
public ObservableCollection<CategoryTreeNode> TreeNodes { get; } = [];
|
||||||
|
|
||||||
|
private CategoryTreeNode? _selectedTreeNode;
|
||||||
|
public CategoryTreeNode? SelectedTreeNode
|
||||||
|
{
|
||||||
|
get => _selectedTreeNode;
|
||||||
|
set => SetProperty(ref _selectedTreeNode, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CategoryDictionaryManagementViewModel(
|
||||||
|
IJeecgCategorySyncService categorySyncService,
|
||||||
|
IContainerExtension container,
|
||||||
|
IRegionManager regionManager) : base(container, regionManager)
|
||||||
|
{
|
||||||
|
_categorySyncService = categorySyncService;
|
||||||
|
_paginationDataGridViewModel = new PaginationDataGridViewModel<JeecgCategoryItemOutput>(FetchAsync);
|
||||||
|
_input = new PageJeecgCategoryItemInput();
|
||||||
|
|
||||||
|
SearchCommand = new DelegateCommand(async () => await SearchAsync());
|
||||||
|
ResetCommand = new DelegateCommand(async () => await ResetAsync());
|
||||||
|
SyncCommand = new DelegateCommand(async () => await SyncAsync());
|
||||||
|
|
||||||
|
_ = InitializeAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
await LoadTreeAsync();
|
||||||
|
await UIHelper.WaitForRenderAsync();
|
||||||
|
await PaginationDataGridViewModel.LoadDataAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<(IEnumerable<JeecgCategoryItemOutput> data, int totalCount)> FetchAsync()
|
||||||
|
{
|
||||||
|
Input.Page = PaginationDataGridViewModel.PageIndex;
|
||||||
|
Input.PageSize = PaginationDataGridViewModel.DataCountPerPage;
|
||||||
|
var result = await _categorySyncService.PageAsync(Input);
|
||||||
|
return (result.Items, result.Total);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SearchAsync()
|
||||||
|
{
|
||||||
|
PaginationDataGridViewModel.PageIndex = 1;
|
||||||
|
await PaginationDataGridViewModel.LoadDataAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ResetAsync()
|
||||||
|
{
|
||||||
|
Input = new PageJeecgCategoryItemInput();
|
||||||
|
SelectedTreeNode = null;
|
||||||
|
await UIHelper.WaitForRenderAsync();
|
||||||
|
await LoadTreeAsync();
|
||||||
|
await SearchAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SyncAsync()
|
||||||
|
{
|
||||||
|
var count = await _categorySyncService.SyncFromJeecgAsync();
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
Growl.Success($"同步完成,共处理 {count} 条分类字典数据");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Growl.Warning("未同步到分类字典,请确认后端可访问");
|
||||||
|
}
|
||||||
|
await LoadTreeAsync();
|
||||||
|
await SearchAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task OnTreeSelectedAsync(CategoryTreeNode? node)
|
||||||
|
{
|
||||||
|
SelectedTreeNode = node;
|
||||||
|
Input.Pid = node?.Id;
|
||||||
|
await SearchAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadTreeAsync()
|
||||||
|
{
|
||||||
|
TreeNodes.Clear();
|
||||||
|
var tree = await _categorySyncService.LoadTreeAsync();
|
||||||
|
foreach (var item in tree)
|
||||||
|
{
|
||||||
|
TreeNodes.Add(MapTreeNode(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CategoryTreeNode MapTreeNode(JeecgCategoryTreeNodeDto dto)
|
||||||
|
{
|
||||||
|
var node = new CategoryTreeNode
|
||||||
|
{
|
||||||
|
Id = dto.Id,
|
||||||
|
Name = dto.Name ?? dto.Code ?? dto.Id,
|
||||||
|
Code = dto.Code
|
||||||
|
};
|
||||||
|
foreach (var child in dto.Children)
|
||||||
|
{
|
||||||
|
node.Children.Add(MapTreeNode(child));
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CategoryTreeNode
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
public string? Name { get; set; }
|
||||||
|
public string? Code { get; set; }
|
||||||
|
public ObservableCollection<CategoryTreeNode> Children { get; set; } = [];
|
||||||
|
public string DisplayName => string.IsNullOrWhiteSpace(Code) ? (Name ?? Id) : $"{Name} ({Code})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
<UserControl x:Class="YY.Admin.Views.MixerMaterial.MixerMaterialEditDialogView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||||
|
xmlns:prism="http://prismlibrary.com/"
|
||||||
|
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Width="760"
|
||||||
|
MinHeight="420">
|
||||||
|
|
||||||
|
<Grid Background="{DynamicResource ThirdlyRegionBrush}">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<hc:SimplePanel Margin="20">
|
||||||
|
<TextBlock FontSize="18" Foreground="{DynamicResource PrimaryTextBrush}" Text="{Binding DialogTitle}" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||||
|
<Button Width="22" Height="22" Command="hc:ControlCommands.Close" Style="{StaticResource ButtonIcon}"
|
||||||
|
Foreground="{DynamicResource PrimaryBrush}" hc:IconElement.Geometry="{StaticResource ErrorGeometry}"
|
||||||
|
Padding="0" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,4,4,0"/>
|
||||||
|
</hc:SimplePanel>
|
||||||
|
|
||||||
|
<hc:ScrollViewer Grid.Row="1" IsInertiaEnabled="True">
|
||||||
|
<StackPanel Margin="20,0,20,0">
|
||||||
|
<hc:Row Gutter="10">
|
||||||
|
<hc:Col Span="12">
|
||||||
|
<hc:TextBox Text="{Binding Material.MaterialCode, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
hc:InfoElement.Title="物料编码"
|
||||||
|
hc:InfoElement.TitleWidth="90"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
hc:InfoElement.Necessary="True"
|
||||||
|
hc:InfoElement.Symbol="*"
|
||||||
|
hc:InfoElement.Placeholder="请输入物料编码"
|
||||||
|
hc:InfoElement.ShowClearButton="True"
|
||||||
|
Margin="0,0,0,16"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Span="12">
|
||||||
|
<hc:TextBox Text="{Binding Material.MaterialName, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
hc:InfoElement.Title="物料名称"
|
||||||
|
hc:InfoElement.TitleWidth="90"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
hc:InfoElement.Necessary="True"
|
||||||
|
hc:InfoElement.Symbol="*"
|
||||||
|
hc:InfoElement.Placeholder="请输入物料名称"
|
||||||
|
hc:InfoElement.ShowClearButton="True"
|
||||||
|
Margin="0,0,0,16"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Span="12">
|
||||||
|
<hc:TextBox Text="{Binding Material.ErpCode, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
hc:InfoElement.Title="ERP编号"
|
||||||
|
hc:InfoElement.TitleWidth="90"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
hc:InfoElement.Placeholder="请输入ERP编号"
|
||||||
|
hc:InfoElement.ShowClearButton="True"
|
||||||
|
Margin="0,0,0,16"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Span="12">
|
||||||
|
<hc:ComboBox SelectedValuePath="Value"
|
||||||
|
DisplayMemberPath="Key"
|
||||||
|
ItemsSource="{Binding MajorCategoryOptions}"
|
||||||
|
SelectedValue="{Binding Material.MajorCategoryId}"
|
||||||
|
SelectionChanged="MajorCategoryComboBox_SelectionChanged"
|
||||||
|
hc:InfoElement.Title="物料大类"
|
||||||
|
hc:InfoElement.TitleWidth="90"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
hc:InfoElement.Necessary="True"
|
||||||
|
hc:InfoElement.Symbol="*"
|
||||||
|
Margin="0,0,0,16"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Span="12">
|
||||||
|
<hc:ComboBox SelectedValuePath="Value"
|
||||||
|
DisplayMemberPath="Key"
|
||||||
|
ItemsSource="{Binding MinorCategoryOptions}"
|
||||||
|
SelectedValue="{Binding Material.MinorCategoryId}"
|
||||||
|
hc:InfoElement.Title="物料小类"
|
||||||
|
hc:InfoElement.TitleWidth="90"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
hc:InfoElement.Necessary="True"
|
||||||
|
hc:InfoElement.Symbol="*"
|
||||||
|
Margin="0,0,0,16"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Span="12">
|
||||||
|
<hc:TextBox Text="{Binding Material.AliasName, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
hc:InfoElement.Title="物料别名"
|
||||||
|
hc:InfoElement.TitleWidth="90"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
hc:InfoElement.Placeholder="请输入物料别名"
|
||||||
|
hc:InfoElement.ShowClearButton="True"
|
||||||
|
Margin="0,0,0,16"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Span="12">
|
||||||
|
<hc:ComboBox SelectedValuePath="Value"
|
||||||
|
DisplayMemberPath="Key"
|
||||||
|
ItemsSource="{Binding FeedManageStatusOptions}"
|
||||||
|
SelectedValue="{Binding Material.FeedManageStatus}"
|
||||||
|
hc:InfoElement.Title="投管状态"
|
||||||
|
hc:InfoElement.TitleWidth="90"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
Margin="0,0,0,16"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Span="12">
|
||||||
|
<hc:ComboBox SelectedValuePath="Value"
|
||||||
|
DisplayMemberPath="Key"
|
||||||
|
ItemsSource="{Binding UseStatusOptions}"
|
||||||
|
SelectedValue="{Binding Material.UseStatus}"
|
||||||
|
hc:InfoElement.Title="使用状态"
|
||||||
|
hc:InfoElement.TitleWidth="90"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
Margin="0,0,0,16"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Span="12">
|
||||||
|
<hc:NumericUpDown Value="{Binding Material.SpecificGravity}" Minimum="0" DecimalPlaces="4"
|
||||||
|
Style="{StaticResource NumericUpDownPlus}"
|
||||||
|
hc:InfoElement.Title="比重"
|
||||||
|
hc:InfoElement.TitleWidth="90"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
Margin="0,0,0,16"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Span="12">
|
||||||
|
<hc:NumericUpDown Value="{Binding Material.ShelfLifeDays}" Minimum="0" DecimalPlaces="0"
|
||||||
|
Style="{StaticResource NumericUpDownPlus}"
|
||||||
|
hc:InfoElement.Title="保质期(天)"
|
||||||
|
hc:InfoElement.TitleWidth="90"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
Margin="0,0,0,16"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Span="12">
|
||||||
|
<hc:NumericUpDown Value="{Binding Material.MinBakeMinutes}" Minimum="0" DecimalPlaces="0"
|
||||||
|
Style="{StaticResource NumericUpDownPlus}"
|
||||||
|
hc:InfoElement.Title="最短烘胶(分)"
|
||||||
|
hc:InfoElement.TitleWidth="90"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
Margin="0,0,0,16"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Span="12">
|
||||||
|
<hc:NumericUpDown Value="{Binding Material.TotalSafetyStockKg}" Minimum="0" DecimalPlaces="4"
|
||||||
|
Style="{StaticResource NumericUpDownPlus}"
|
||||||
|
hc:InfoElement.Title="总安全库存KG"
|
||||||
|
hc:InfoElement.TitleWidth="90"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
Margin="0,0,0,16"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Span="12">
|
||||||
|
<hc:NumericUpDown Value="{Binding Material.QualifiedSafetyStockKg}" Minimum="0" DecimalPlaces="4"
|
||||||
|
Style="{StaticResource NumericUpDownPlus}"
|
||||||
|
hc:InfoElement.Title="合格库存KG"
|
||||||
|
hc:InfoElement.TitleWidth="90"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
Margin="0,0,0,16"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Span="24">
|
||||||
|
<hc:TextBox Text="{Binding Material.MaterialDesc, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
hc:InfoElement.Title="物料描述"
|
||||||
|
hc:InfoElement.TitleWidth="90"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
hc:InfoElement.Placeholder="请输入物料描述"
|
||||||
|
hc:InfoElement.ShowClearButton="True"
|
||||||
|
Margin="0,0,0,16"/>
|
||||||
|
</hc:Col>
|
||||||
|
</hc:Row>
|
||||||
|
</StackPanel>
|
||||||
|
</hc:ScrollViewer>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center" Margin="20">
|
||||||
|
<Button Content="取消" Command="{Binding CancelCommand}" Style="{StaticResource ButtonDefault}" Margin="0,0,15,0" Width="100"/>
|
||||||
|
<Button Content="确定" Command="{Binding SaveCommand}" Style="{StaticResource ButtonPrimary}" Width="100"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Windows.Controls;
|
||||||
|
using YY.Admin.ViewModels.MixerMaterial;
|
||||||
|
|
||||||
|
namespace YY.Admin.Views.MixerMaterial;
|
||||||
|
|
||||||
|
public partial class MixerMaterialEditDialogView : UserControl
|
||||||
|
{
|
||||||
|
public MixerMaterialEditDialogView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MajorCategoryComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (DataContext is MixerMaterialEditDialogViewModel vm && vm.MajorCategoryChangedCommand.CanExecute())
|
||||||
|
{
|
||||||
|
vm.MajorCategoryChangedCommand.Execute();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,174 @@
|
|||||||
|
<UserControl x:Class="YY.Admin.Views.MixerMaterial.MixerMaterialListView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||||
|
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
xmlns:prism="http://prismlibrary.com/"
|
||||||
|
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<Grid Style="{StaticResource BaseViewStyle}">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Border Grid.Row="0" CornerRadius="4" Margin="0 0 -10 0">
|
||||||
|
<hc:Row>
|
||||||
|
<hc:Col Layout="{hc:ColLayout Xs=12, Sm=8, Md=6, Lg=6, Xl=4}">
|
||||||
|
<hc:TextBox Text="{Binding FilterMaterialCode, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
Margin="0 0 10 10"
|
||||||
|
hc:InfoElement.Title="物料编码"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
hc:InfoElement.TitleWidth="65"
|
||||||
|
hc:InfoElement.Placeholder="请输入物料编码"
|
||||||
|
hc:InfoElement.ShowClearButton="True"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Layout="{hc:ColLayout Xs=12, Sm=8, Md=6, Lg=6, Xl=4}">
|
||||||
|
<hc:TextBox Text="{Binding FilterMaterialName, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
Margin="0 0 10 10"
|
||||||
|
hc:InfoElement.Title="物料名称"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
hc:InfoElement.TitleWidth="65"
|
||||||
|
hc:InfoElement.Placeholder="请输入物料名称"
|
||||||
|
hc:InfoElement.ShowClearButton="True"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Layout="{hc:ColLayout Xs=12, Sm=8, Md=6, Lg=6, Xl=4}">
|
||||||
|
<hc:TextBox Text="{Binding FilterErpCode, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
Margin="0 0 10 10"
|
||||||
|
hc:InfoElement.Title="ERP编号"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
hc:InfoElement.TitleWidth="65"
|
||||||
|
hc:InfoElement.Placeholder="请输入ERP编号"
|
||||||
|
hc:InfoElement.ShowClearButton="True"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Layout="{hc:ColLayout Xs=12, Sm=8, Md=6, Lg=6, Xl=4}">
|
||||||
|
<hc:ComboBox SelectedValuePath="Value"
|
||||||
|
DisplayMemberPath="Key"
|
||||||
|
ItemsSource="{Binding MajorCategoryOptions}"
|
||||||
|
SelectedValue="{Binding FilterMajorCategoryId}"
|
||||||
|
Margin="0 0 10 10"
|
||||||
|
hc:InfoElement.Title="物料大类"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
hc:InfoElement.TitleWidth="65"
|
||||||
|
hc:InfoElement.Placeholder="请选择物料大类"
|
||||||
|
hc:InfoElement.ShowClearButton="True"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Layout="{hc:ColLayout Xs=12, Sm=8, Md=6, Lg=6, Xl=4}">
|
||||||
|
<hc:ComboBox SelectedValuePath="Value"
|
||||||
|
DisplayMemberPath="Key"
|
||||||
|
ItemsSource="{Binding MinorCategoryOptions}"
|
||||||
|
SelectedValue="{Binding FilterMinorCategoryId}"
|
||||||
|
Margin="0 0 10 10"
|
||||||
|
hc:InfoElement.Title="物料小类"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
hc:InfoElement.TitleWidth="65"
|
||||||
|
hc:InfoElement.Placeholder="请选择物料小类"
|
||||||
|
hc:InfoElement.ShowClearButton="True"/>
|
||||||
|
</hc:Col>
|
||||||
|
</hc:Row>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Border Grid.Row="1" Margin="0,10">
|
||||||
|
<hc:UniformSpacingPanel Spacing="10">
|
||||||
|
<Button Style="{StaticResource ButtonPrimary}" Command="{Binding SearchCommand}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<md:PackIcon Kind="Search"/>
|
||||||
|
<TextBlock Text="搜索" Style="{StaticResource IconButtonStyle}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Button Style="{StaticResource ButtonDefault}" Command="{Binding ResetCommand}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<md:PackIcon Kind="Refresh"/>
|
||||||
|
<TextBlock Text="重置" Style="{StaticResource IconButtonStyle}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Button Style="{StaticResource ButtonSuccess}" Command="{Binding AddCommand}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<md:PackIcon Kind="Plus"/>
|
||||||
|
<TextBlock Text="新增" Style="{StaticResource IconButtonStyle}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</hc:UniformSpacingPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<DataGrid Grid.Row="2"
|
||||||
|
ItemsSource="{Binding Materials}"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
IsReadOnly="True"
|
||||||
|
CanUserAddRows="False"
|
||||||
|
SelectionMode="Extended"
|
||||||
|
SelectionUnit="FullRow"
|
||||||
|
RowHeaderWidth="55"
|
||||||
|
GridLinesVisibility="Horizontal"
|
||||||
|
HorizontalGridLinesBrush="#FFEDEDED"
|
||||||
|
VerticalGridLinesBrush="Transparent"
|
||||||
|
HeadersVisibility="All"
|
||||||
|
ColumnHeaderStyle="{StaticResource CusDataGridColumnHeaderStyle}"
|
||||||
|
Style="{StaticResource CusDataGridStyle}"
|
||||||
|
hc:DataGridAttach.ShowSelectAllButton="True"
|
||||||
|
VerticalScrollBarVisibility="Auto"
|
||||||
|
HorizontalScrollBarVisibility="Auto">
|
||||||
|
<DataGrid.RowHeaderTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<CheckBox IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=DataGridRow}}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</DataGrid.RowHeaderTemplate>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="物料编码" Binding="{Binding MaterialCode}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="120"/>
|
||||||
|
<DataGridTextColumn Header="物料名称" Binding="{Binding MaterialName}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="140"/>
|
||||||
|
<DataGridTextColumn Header="ERP编号" Binding="{Binding ErpCode}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="120"/>
|
||||||
|
<DataGridTextColumn Header="物料大类" Binding="{Binding MajorCategoryText}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="120"/>
|
||||||
|
<DataGridTextColumn Header="物料小类" Binding="{Binding MinorCategoryText}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="120"/>
|
||||||
|
<DataGridTextColumn Header="物料描述" Binding="{Binding MaterialDesc}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="160"/>
|
||||||
|
<DataGridTextColumn Header="物料别名" Binding="{Binding AliasName}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="120"/>
|
||||||
|
<DataGridTextColumn Header="投管状态" Binding="{Binding FeedManageStatusText}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="100"/>
|
||||||
|
<DataGridTextColumn Header="使用状态" Binding="{Binding UseStatusText}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="100"/>
|
||||||
|
<DataGridTextColumn Header="比重" Binding="{Binding SpecificGravity, StringFormat=N4}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="90"/>
|
||||||
|
<DataGridTextColumn Header="保质期(天)" Binding="{Binding ShelfLifeDays}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="100"/>
|
||||||
|
<DataGridTemplateColumn Header="操作" Width="150" CellStyle="{StaticResource CusOperDataGridCellStyle}">
|
||||||
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<hc:UniformSpacingPanel Spacing="5">
|
||||||
|
<Border Style="{DynamicResource DataGridOpeButtonStyle}">
|
||||||
|
<Border.InputBindings>
|
||||||
|
<MouseBinding Command="{Binding DataContext.EditCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}"
|
||||||
|
CommandParameter="{Binding}" MouseAction="LeftClick"/>
|
||||||
|
</Border.InputBindings>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<md:PackIcon Kind="SquareEditOutline" VerticalAlignment="Center"/>
|
||||||
|
<TextBlock Text="修改" VerticalAlignment="Center"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
<Border Style="{DynamicResource DataGridOpeButtonStyle}">
|
||||||
|
<Border.InputBindings>
|
||||||
|
<MouseBinding Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource AncestorType=DataGrid}}"
|
||||||
|
CommandParameter="{Binding}" MouseAction="LeftClick"/>
|
||||||
|
</Border.InputBindings>
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<md:PackIcon Kind="TrashCanOutline" VerticalAlignment="Center"/>
|
||||||
|
<TextBlock Text="删除" VerticalAlignment="Center"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</hc:UniformSpacingPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
|
</DataGridTemplateColumn>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,10,0,0">
|
||||||
|
<TextBlock Text="{Binding Total, StringFormat=共 {0} 条}" VerticalAlignment="Center" Margin="0,0,16,0"
|
||||||
|
Foreground="{DynamicResource SecondaryTextBrush}"/>
|
||||||
|
<Button Content="上一页" Command="{Binding PrevPageCommand}" Style="{StaticResource ButtonDefault}" Margin="0,0,4,0" Width="80"/>
|
||||||
|
<TextBlock Text="{Binding PageNo, StringFormat=第 {0} 页}" VerticalAlignment="Center" Margin="8,0"
|
||||||
|
Foreground="{DynamicResource PrimaryTextBrush}"/>
|
||||||
|
<Button Content="下一页" Command="{Binding NextPageCommand}" Style="{StaticResource ButtonDefault}" Width="80"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace YY.Admin.Views.MixerMaterial;
|
||||||
|
|
||||||
|
public partial class MixerMaterialListView : UserControl
|
||||||
|
{
|
||||||
|
public MixerMaterialListView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
<UserControl x:Class="YY.Admin.Views.SysManage.CategoryDictionaryManagementView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:hc="https://handyorg.github.io/handycontrol"
|
||||||
|
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
xmlns:components="clr-namespace:YY.Admin.Views.Control"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
|
||||||
|
<Grid Style="{StaticResource BaseViewStyle}">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Border Grid.Row="0" CornerRadius="4" Margin="0 0 -10 0">
|
||||||
|
<hc:Row>
|
||||||
|
<hc:Col Layout="{hc:ColLayout Xs=12, Sm=8, Md=6, Lg=6, Xl=4}">
|
||||||
|
<hc:TextBox
|
||||||
|
Text="{Binding Input.Code, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
hc:InfoElement.Placeholder="请输入分类编码"
|
||||||
|
hc:InfoElement.Title="分类编码"
|
||||||
|
hc:InfoElement.TitleWidth="70"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
hc:InfoElement.ShowClearButton="True"
|
||||||
|
Margin="0 0 10 10"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Layout="{hc:ColLayout Xs=12, Sm=8, Md=6, Lg=6, Xl=4}">
|
||||||
|
<hc:TextBox
|
||||||
|
Text="{Binding Input.Name, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
hc:InfoElement.Placeholder="请输入分类名称"
|
||||||
|
hc:InfoElement.Title="分类名称"
|
||||||
|
hc:InfoElement.TitleWidth="70"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
hc:InfoElement.ShowClearButton="True"
|
||||||
|
Margin="0 0 10 10"/>
|
||||||
|
</hc:Col>
|
||||||
|
<hc:Col Layout="{hc:ColLayout Xs=12, Sm=8, Md=6, Lg=6, Xl=4}">
|
||||||
|
<hc:TextBox
|
||||||
|
Text="{Binding Input.Pid, UpdateSourceTrigger=PropertyChanged}"
|
||||||
|
hc:InfoElement.Placeholder="请输入父级ID"
|
||||||
|
hc:InfoElement.Title="父级ID"
|
||||||
|
hc:InfoElement.TitleWidth="70"
|
||||||
|
hc:InfoElement.TitlePlacement="Left"
|
||||||
|
hc:InfoElement.ShowClearButton="True"
|
||||||
|
Margin="0 0 10 10"/>
|
||||||
|
</hc:Col>
|
||||||
|
</hc:Row>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Border Grid.Row="1" Margin="0,10">
|
||||||
|
<hc:UniformSpacingPanel Spacing="10">
|
||||||
|
<Button Style="{StaticResource ButtonPrimary}" Command="{Binding SearchCommand}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<md:PackIcon Kind="Search"/>
|
||||||
|
<TextBlock Text="搜索" Style="{StaticResource IconButtonStyle}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Button Style="{StaticResource ButtonDefault}" Command="{Binding ResetCommand}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<md:PackIcon Kind="Refresh"/>
|
||||||
|
<TextBlock Text="重置" Style="{StaticResource IconButtonStyle}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Button Style="{StaticResource ButtonSuccess}" Command="{Binding SyncCommand}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<md:PackIcon Kind="CloudSyncOutline"/>
|
||||||
|
<TextBlock Text="同步分类字典" Style="{StaticResource IconButtonStyle}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</hc:UniformSpacingPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Grid Grid.Row="2">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="300"/>
|
||||||
|
<ColumnDefinition Width="10"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Border Grid.Column="0" BorderBrush="#FFEDEDED" BorderThickness="1" CornerRadius="4" Padding="8">
|
||||||
|
<TreeView x:Name="CategoryTreeView"
|
||||||
|
ItemsSource="{Binding TreeNodes}"
|
||||||
|
SelectedItemChanged="CategoryTreeView_SelectedItemChanged">
|
||||||
|
<TreeView.ItemTemplate>
|
||||||
|
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
|
||||||
|
<TextBlock Text="{Binding DisplayName}" />
|
||||||
|
</HierarchicalDataTemplate>
|
||||||
|
</TreeView.ItemTemplate>
|
||||||
|
</TreeView>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<DataGrid
|
||||||
|
Grid.Column="2"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
HeadersVisibility="All"
|
||||||
|
ItemsSource="{Binding PaginationDataGridViewModel.Data}"
|
||||||
|
ColumnHeaderStyle="{StaticResource CusDataGridColumnHeaderStyle}"
|
||||||
|
Style="{StaticResource CusDataGridStyle}">
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn IsReadOnly="True" Binding="{Binding Code}" Header="分类编码" Width="200" CellStyle="{StaticResource CusDataGridCellStyle}"/>
|
||||||
|
<DataGridTextColumn IsReadOnly="True" Binding="{Binding Name}" Header="分类名称" Width="200" CellStyle="{StaticResource CusDataGridCellStyle}"/>
|
||||||
|
<DataGridTextColumn IsReadOnly="True" Binding="{Binding Pid}" Header="父级ID" Width="220" CellStyle="{StaticResource CusDataGridCellStyle}"/>
|
||||||
|
<DataGridTextColumn IsReadOnly="True" Binding="{Binding HasChild}" Header="有子级" Width="80" CellStyle="{StaticResource CusDataGridCellStyle}"/>
|
||||||
|
<DataGridTextColumn IsReadOnly="True" Binding="{Binding CreateTime, StringFormat='yyyy-MM-dd HH:mm:ss'}" Header="创建时间" Width="170" CellStyle="{StaticResource CusDataGridCellStyle}"/>
|
||||||
|
<DataGridTextColumn IsReadOnly="True" Binding="{Binding UpdateTime, StringFormat='yyyy-MM-dd HH:mm:ss'}" Header="更新时间" Width="170" CellStyle="{StaticResource CusDataGridCellStyle}"/>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<components:PaginationDataGridControl Grid.Row="3" DataContext="{Binding PaginationDataGridViewModel}"/>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
|
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows;
|
||||||
|
using YY.Admin.ViewModels.SysManage;
|
||||||
|
|
||||||
|
namespace YY.Admin.Views.SysManage
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// CategoryDictionaryManagementView.xaml 的交互逻辑
|
||||||
|
/// </summary>
|
||||||
|
public partial class CategoryDictionaryManagementView : UserControl
|
||||||
|
{
|
||||||
|
public CategoryDictionaryManagementView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void CategoryTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
|
||||||
|
{
|
||||||
|
if (DataContext is CategoryDictionaryManagementViewModel vm)
|
||||||
|
{
|
||||||
|
await vm.OnTreeSelectedAsync(e.NewValue as CategoryDictionaryManagementViewModel.CategoryTreeNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user