XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

STHApplication

【MAUI】寄当家——安卓端交易管理系统

公开
关注 0 Fork 0 Star 0
UTF-8
using JiDangJia.Core;
using System.Text.Json;

namespace JiDangJia.Views;

public sealed class RecordsPage : ContentPage
{
    static RecordsPage(){Names["FundingAccount"]="资方资金";Names["FundingSettlement"]="资金成本结算";}
    private readonly BusinessService service;
    private readonly string table;
    private readonly VerticalStackLayout list=Ui.Stack();
    private readonly Entry search=new() {Placeholder="搜索姓名、电话、编号",ClearButtonVisibility=ClearButtonVisibility.WhileEditing,ReturnType=ReturnType.Search};
    public RecordsPage(BusinessService service,string table)
    {
        this.service=service;this.table=table;Title=Names.GetValueOrDefault(table,table);
        var body=Ui.Stack(Ui.Card(search,13,new Thickness(12,0),Ui.Paper));body.Padding=18;
        if(table=="Customer")body.Add(Ui.Button("+ 新建客户",()=>Navigation.PushAsync(FormPage.Customer(service))));
        body.Add(list);Content=new ScrollView {Content=body};search.TextChanged+=(_,_)=>Load();
    }
    public static readonly Dictionary<string,string> Names=new(){["Customer"]="客户档案",["PawnTicket"]="当单管理",["RecycleOrder"]="入库单",["RecycleItem"]="库存物品",["SaleRecord"]="销售记录",["BusinessOrder"]="业务记录",["FinanceRecord"]="财务流水",["OperationLog"]="操作日志",["Reminder"]="到期提醒",["User"]="员工管理",["PawnItemTypeRate"]="当物类型与费率",["FinanceCategory"]="财务分类",["PrintTemplate"]="打印模板",["Advertisement"]="广告管理"};
    protected override void OnAppearing() {base.OnAppearing();Load();}
    private void Load()
    {
        list.Clear();
        var records=table=="Reminder"?service.Db.Query("SELECT * FROM PawnTicket WHERE status='ACTIVE' AND deletedAt IS NULL AND dueDate<=@p0 ORDER BY dueDate",Display.Day(DateTime.Today.AddDays(7))):service.Db.Query($"SELECT * FROM [{table}] ORDER BY createdAt DESC");
        records=records.Where(r=>r.Text("deletedAt").Length==0&&(string.IsNullOrWhiteSpace(search.Text)||r.Values.Any(v=>v?.ToString()?.Contains(search.Text,StringComparison.OrdinalIgnoreCase)==true))).ToList();
        list.Add(Ui.Text(records.Count+" 条记录",12,Ui.Muted));
        if(records.Count==0){list.Add(Ui.Card(Ui.Empty("暂无记录","有新数据时会在这里显示")));return;}
        foreach(var record in records)
        {
            string name=record.Text("name",record.Text("itemName",record.Text("label",record.Text("targetName",service.Category(record.Text("category"))))));
            string code=record.Text("code",record.Text("ticketNo",record.Text("orderNo",record.Text("saleNo",record.Text("occurDate",record.Text("createdAt"))))));
            var main=Ui.Stack(Ui.Text(name,17,bold:true),Ui.Text(code,11,Ui.Muted));
            var amount=record.Money("principal")!=0?record.Money("principal"):record.Money("amount");
            var title=Ui.Spread(main,table=="Customer"?Ui.Pill(record.Int("isBlacklist")==1?"黑名单":record.Text("type")=="COMPANY"?"企业":"个人"):amount!=0?Ui.Text(Display.Money(amount),17,Ui.Bronze,true):Ui.Icon("chevron",Ui.Muted,15));
            var body=Ui.Stack(title);
            if(table=="Customer") {body.Add(Ui.Text(record.Text("phone","未填写电话"),12,Ui.Muted));var stats=service.Db.Query("SELECT COUNT(*) cnt,COALESCE(SUM(principal),0) total FROM PawnTicket WHERE customerId=@p0 AND deletedAt IS NULL",record.Id).First();body.Add(Ui.Divider());body.Add(Ui.Spread(Ui.Text($"累计 {stats.Text("cnt")} 笔 · {Display.Money(stats.Money("total"))}",12,Ui.Bronze),Ui.Button("+ 开当",()=>Navigation.PushAsync(FormPage.Order(service,"PAWN",record.Id)))));}
            if(table=="Reminder")body.Add(Ui.Text("到期 "+record.Text("dueDate")+" · "+record.Text("customerName"),12,record.Date("dueDate")<DateTime.Today?Ui.Red:Ui.Bronze));
            string target=table=="Reminder"?"PawnTicket":table;
            var card=Ui.Card(body);if(target=="PawnTicket"){var state=PawnState.State(record,DateTime.Today,service.Shop.Int("nearExpireDays"));body.Add(Ui.Text(Display.Status(state),12,state=="OVERDUE"?Ui.Red:state=="DEAD"?Ui.Ink:Ui.Bronze));Ui.PawnOutline(card,state);}list.Add(Ui.Tap(card,()=>Navigation.PushAsync(new DetailPage(service,target,record.Id))));
        }
    }
}

public sealed class DetailPage : ContentPage
{
    private readonly BusinessService service;
    private readonly string table,id;
    private readonly VerticalStackLayout body=Ui.Stack();
    public DetailPage(BusinessService service,string table,string id)
    {
        this.service=service;this.table=table;this.id=id;Title=RecordsPage.Names.GetValueOrDefault(table,"记录")+"详情";body.Padding=18;Content=new ScrollView {Content=body};
    }
    protected override void OnAppearing() {base.OnAppearing();Load();}
    private void Load()
    {
        body.Clear();var row=service.Db.Find(table,id);if(row is null) {body.Add(Ui.Empty("记录不存在","记录可能已经被删除"));return;}
        if(row.Text("deletedAt").Length>0){body.Add(Ui.Empty("记录在回收站中","请在设置的回收站中还原或永久删除"));return;}
        var state=table=="PawnTicket"?PawnState.State(row,DateTime.Today,service.Shop.Int("nearExpireDays")):row.Text("status");
        if(table=="RecycleItem" && row.Text("source")=="RENTAL")state=RentalInventory.Status(row,service.Db.Find("BusinessOrder",row.Text("rentalOrderId")),DateTime.Today);
        var name=row.Text("name",row.Text("itemName",row.Text("label",row.Text("title",RecordsPage.Names.GetValueOrDefault(table,"记录")))));
        var head=Ui.Stack(Ui.Spread(Ui.Text(name,24,bold:true),Ui.Pill(Display.Status(state),state=="OVERDUE"?Ui.Red:Ui.Bronze)),Ui.Text(row.Text("ticketNo",row.Text("orderNo",row.Text("saleNo",row.Text("code")))),12,Ui.Muted));
        if(row.Money("principal")>0||row.Money("amount")>0)head.Add(Ui.Text(Display.Money(row.Money(table=="PawnTicket"?"principal":"amount")),30,Ui.Bronze,true));body.Add(Ui.Card(head));
        var details=Ui.Stack(Ui.Section("详细信息"));
        foreach(var pair in row)
        {
            if(pair.Value is null || !FieldLabels.TryGetValue(pair.Key,out var label)||pair.Key is "images" or "contractImages" or "idCardImages" || row.Text(pair.Key).Length==0)continue;
            if(table=="BusinessOrder" && (row.Text("kind")=="CONSIGN"&&pair.Key=="deposit" || row.Text("kind")!="CONSIGN"&&pair.Key is "commission" or "serviceFeeMode" or "serviceFeeValue" or "storageFee" or "expectedAmount"))continue;
            if(table=="RecycleItem" && row.Text("type") is "PROPERTY" or "VEHICLE" && pair.Key is "weight" or "spec" or "unitPrice")continue;
            if(table=="BusinessOrder" && row.Text("kind")=="CONSIGN")label=pair.Key switch{"amount"=>"实际成交金额","commission"=>"实收服务费","serviceFeeValue"=>row.Text("serviceFeeMode")=="PERCENT"?"服务费比例(%)":"固定服务费(元)",_=>label};
            string value=pair.Key switch {"majorClass"=>FinanceAnalytics.Majors.GetValueOrDefault(row.Text(pair.Key),row.Text(pair.Key)),"detailClass"=>FinanceAnalytics.DetailLabel(row.Text("majorClass"),row.Text(pair.Key)),"type" when table=="Customer"=>row.Text("type")=="COMPANY"?"企业":"个人","type" when table=="FinanceRecord"=>row.Text("type")=="INCOME"?"收入":"支出","itemType" or "type"=>service.ItemType(row.Text(pair.Key)),"material" when ItemCatalog.Category(row.Text("type"))=="METAL"=>ItemCatalog.MaterialName(row.Text(pair.Key)),"serviceFeeMode"=>row.Text(pair.Key)=="PERCENT"?"百分比":"固定金额","status"=>Display.Status(state),"category"=>service.Category(row.Text(pair.Key)),"action"=>Display.Action(row.Text(pair.Key)),"creditLevel"=>new Dictionary<string,string>{{"NORMAL","普通"},{"GOOD","良好"},{"VIP","VIP"},{"RISK","风险"}}.GetValueOrDefault(row.Text(pair.Key),row.Text(pair.Key)),"isBlacklist"=>row.Int(pair.Key)==1?"是":"否","createdAt" or "updatedAt"=>row.Date(pair.Key).ToLocalTime().ToString("yyyy-MM-dd HH:mm"),"payMethod"=>FormPage.PaymentMethods.GetValueOrDefault(row.Text(pair.Key),row.Text(pair.Key)),"feeChargeMode"=>row.Text(pair.Key)=="POSTPAID"?"按期结算":"开当收取",_=>row.Text(pair.Key)};
            details.Add(Ui.Spread(Ui.Text(label,12,Ui.Muted),Ui.Text(value,13)));details.Add(Ui.Divider());
        }
        AddAttributes(details,row);body.Add(Ui.Card(details));
        foreach(var key in new[]{"images","contractImages","idCardImages"})
        {
            var photos=MediaFiles.Parse(row.Text(key));if(photos.Count==0)continue;var images=Ui.Stack(Ui.Section(FieldLabels[key]));
            foreach(var photo in photos)try {images.Add(new Image {Source=MediaFiles.Source(photo),Aspect=Aspect.AspectFit,HeightRequest=220});}catch {images.Add(Ui.Text("此图片来自旧设备,需同时迁移原图片文件",12,Ui.Muted));}body.Add(Ui.Card(images));
        }
        if(table=="FinanceRecord"&&row.Text("category")=="FUNDING_COST")
        {
            var settlement=service.Db.Find("FundingSettlement",row.Text("ticketId"));
            if(settlement is not null)body.Add(Ui.Button("查看关联资方资金",()=>Navigation.PushAsync(new FundingDetailPage(service,settlement.Text("accountId"))),false));
        }
        if(table=="Customer")
        {
            body.Add(Ui.Button("编辑客户",()=>Navigation.PushAsync(FormPage.Customer(service,id))));body.Add(Ui.Button("+ 新建当单",()=>Navigation.PushAsync(FormPage.Order(service,"PAWN",id)),false));
            body.Add(Ui.Button("+ 新建回收单",()=>Navigation.PushAsync(FormPage.Order(service,"RECYCLE",id)),false));
            var history=service.Db.Query("SELECT * FROM PawnTicket WHERE customerId=@p0 AND deletedAt IS NULL ORDER BY createdAt DESC",id);var items=Ui.Stack(Ui.Section("客户业务记录"));
            foreach(var ticket in history) items.Add(Ui.Tap(Ui.Spread(Ui.Text(ticket.Text("ticketNo")+" · "+Display.Status(ticket.Text("status")),12),Ui.Text(Display.Money(ticket.Money("principal")),14,Ui.Bronze)),()=>Navigation.PushAsync(new DetailPage(service,"PawnTicket",ticket.Id))));body.Add(Ui.Card(items));
        }
        if(table is "PawnTicket" or "RecycleOrder")
        {
            var parts=table=="PawnTicket"?service.Db.Query("SELECT * FROM PawnItem WHERE ticketId=@p0",id):service.Db.Query("SELECT * FROM RecycleItem WHERE orderId=@p0",id);
            var items=Ui.Stack(Ui.Section("物品清单"));foreach(var item in parts)AddItem(items,item);body.Add(Ui.Card(items));
            body.Add(Ui.Button("预览 / 打印凭证",()=>Navigation.PushAsync(new PrintPage(service,table,row)),false));
        }
        if(table=="BusinessOrder" && row.Text("items").Length>0)
        {
            var parts=Ui.Stack(Ui.Section(row.Text("kind")=="RENT"?"租赁物品清单":"寄卖物品清单"));
            try{using var doc=JsonDocument.Parse(row.Text("items"));foreach(var item in doc.RootElement.EnumerateArray())AddItem(parts,DbRow.FromJson(item));}catch(JsonException){parts.Add(Ui.Text("物品资料读取失败",12,Ui.Muted));}
            body.Add(Ui.Card(parts));
        }
        if(table=="PawnTicket"&&row.Text("status")=="ACTIVE")
        {
            body.Add(Ui.Button("续当",()=>Navigation.PushAsync(FormPage.Renew(service,id))));
            body.Add(Ui.Button("赎当结算",()=>Navigation.PushAsync(FormPage.Redeem(service,id)),false));
            body.Add(Ui.Button("绝当转入库存",async()=> {if(await DisplayAlertAsync("确认绝当","当物将进入库存,可上架销售。","转入库存","取消")){await Task.Run(()=>service.Dead(id));Load();}},false));
        }
        if(table=="PawnTicket")
        {
            var logs=service.Db.Query("SELECT * FROM OperationLog WHERE targetId=@p0 ORDER BY createdAt DESC",id);var renews=service.Db.Query("SELECT * FROM RenewRecord WHERE ticketId=@p0 ORDER BY createdAt DESC",id);
            var timeline=Ui.Stack(Ui.Section("业务轨迹"));foreach(var r in renews)timeline.Add(Ui.Text($"{r.Text("renewDate")}  续当 · 费用 {Display.Money(r.Money("fee"))} · 到期 {r.Text("newDueDate")}",12,Ui.Muted));foreach(var r in service.Db.Query("SELECT * FROM RedeemRecord WHERE ticketId=@p0 ORDER BY createdAt DESC",id))timeline.Add(Ui.Text($"{r.Text("redeemDate")}  赎当 · 实收 {Display.Money(r.Money("paid"))}",12,Ui.Muted));foreach(var log in logs)timeline.Add(Ui.Text(log.Text("createdAt")[..Math.Min(10,log.Text("createdAt").Length)]+"  "+log.Text("action"),12,Ui.Muted));body.Add(Ui.Card(timeline));
        }
        if(table=="RecycleItem" && row.Text("source")=="RENTAL" && row.Int("costKnown")==0)
        {
            body.Add(Ui.Text("旧租赁物品缺少购货成本,销售结算前请补录,避免利润失真。",12,Ui.Red));
            body.Add(Ui.Button("补录历史购货成本",async()=>{var text=await DisplayPromptAsync("补录购货成本","仅补录历史成本,不新增当前现金支出。赠送物品可填 0。","保存","取消",keyboard:Keyboard.Numeric);if(text is null)return;if(!decimal.TryParse(text,out var cost))throw new ArgumentException("请填写正确的成本");await Task.Run(()=>service.SetRentalCost(id,cost));Load();},false));
        }
        if(table=="RecycleItem"&&row.Text("status") is "IN_STOCK" or "LISTED")
        {
            if(row.Text("source")=="RENTAL")body.Add(Ui.Button("出租此物品",()=>Navigation.PushAsync(FormPage.Order(service,"RENT",stockId:id))));
            body.Add(Ui.Button("上架 / 修改标价",async()=> {var text=await DisplayPromptAsync("上架销售","请输入销售标价(元)","确认","取消",keyboard:Keyboard.Numeric,initialValue:row.Money("listedPrice").ToString("F2"));if(text is null)return;if(!decimal.TryParse(text,out var value))throw new ArgumentException("请输入正确价格");await Task.Run(()=>service.ListStock(id,value));Load();},false));
            body.Add(Ui.Button("销售出库",async()=> {var text=await DisplayPromptAsync("销售出库","请输入实际成交价(元)","下一步","取消",keyboard:Keyboard.Numeric,initialValue:row.Money("listedPrice").ToString("F2"));if(text is null)return;if(!decimal.TryParse(text,out var value))throw new ArgumentException("请输入正确价格");if(await DisplayAlertAsync("确认销售",$"成交 {Display.Money(value)}\n成本 {Display.Money(row.Money("amount"))}\n利润 {Display.Money(value-row.Money("amount"))}","确认收款","取消")){await Task.Run(()=>service.Sell(id,value,"","CASH",DateTime.Today));Load();}}));
        }
        if(table=="RecycleItem" && row.Text("status")=="RENTED")
        {
            body.Add(Ui.Text(state=="OVERDUE_RENT"?"逾期未归还,可在租赁单中办理归还或销售结算。":"租赁中,暂不能销售或再次出租。",13,state=="OVERDUE_RENT"?Ui.Red:Ui.Muted));
            body.Add(Ui.Button("查看当前租赁单",()=>Navigation.PushAsync(new DetailPage(service,"BusinessOrder",row.Text("rentalOrderId"))),false));
            if(state=="OVERDUE_RENT")body.Add(Ui.Button("未归还,按销售结算",()=>Navigation.PushAsync(FormPage.LostRental(service,row.Text("rentalOrderId")))));
        }
        if(table=="BusinessOrder"&&row.Text("status")=="OPEN")
        {
            if(row.Text("kind")=="CONSIGN")body.Add(Ui.Button("录入成交并结算",()=>Navigation.PushAsync(FormPage.SettleConsignment(service,id))));
            else body.Add(Ui.Button(row.Text("kind")=="RENT"?"归还并结算":"完成业务",async()=> {var text=row.Text("kind")=="RENT"?$"收取租金 {Display.Money(row.Money("amount"))},退还押金 {Display.Money(row.Money("deposit"))}。":"确认本次款项已收妥?";if(await DisplayAlertAsync("确认结算",text,"确认已结清","取消")){service.CompleteBusiness(id);Load();}}));
            if(row.Text("kind")=="RENT" && RentalInventory.IsOverdue(row,DateTime.Today))body.Add(Ui.Button("未归还,保留押金并按销售结算",()=>Navigation.PushAsync(FormPage.LostRental(service,id)),false));
            body.Add(Ui.Button("作废业务",async()=>{if(await DisplayAlertAsync("确认作废","确认已归还物品和押金?作废后保留业务记录。","确认作废","取消")){service.VoidBusiness(id);Load();}},false));
        }
        if(table=="SaleRecord"&&row.Text("status")=="DONE")body.Add(Ui.Button("作废销售并退回库存",async()=>{if(await DisplayAlertAsync("确认作废","确认已退回成交款?物品将恢复在库,退款保留在财务流水中。","已退款,作废","取消")){await Task.Run(()=>service.VoidSale(id));Load();}},false));
        if(table=="RecycleOrder"&&row.Text("status")=="DONE")body.Add(Ui.Button("作废入库单",async()=>{if(await DisplayAlertAsync("确认作废","仅允许整单物品仍在库或在售时作废。确认已退回物品并收回入库款?","确认作废","取消")){await Task.Run(()=>service.VoidIntake(id));Load();}},false));
        if(table=="RecycleItem"&&row.Text("orderId").Length>0)body.Add(Ui.Button("查看来源入库单",()=>Navigation.PushAsync(new DetailPage(service,"RecycleOrder",row.Text("orderId"))),false));
        if(table=="RecycleItem"&&row.Text("status")=="SOLD"){var sale=service.Db.Query("SELECT id FROM SaleRecord WHERE itemId=@p0 AND status='DONE' AND deletedAt IS NULL ORDER BY createdAt DESC LIMIT 1",id).FirstOrDefault();if(sale is not null)body.Add(Ui.Button("查看销售记录",()=>Navigation.PushAsync(new DetailPage(service,"SaleRecord",sale.Id)),false));}
        if(RecordLifecycle.Tables.Contains(table))body.Add(Ui.Button("移入回收站",async()=> {if(await DisplayAlertAsync("移入回收站","该记录及关联业务、库存和流水将退出正常列表与统计,可在回收站一起还原。此操作不代表退款或实物归还。","移入","取消")){await Task.Run(()=>service.SoftDelete(table,id));await Navigation.PopAsync();}},false));
        var phone=row.Text("customerPhone",row.Text("phone"));if(phone.Length>0)body.Add(Ui.Button("拨打客户电话",()=> {PhoneDialer.Default.Open(phone);return Task.CompletedTask;},false));
    }
    private void AddItem(VerticalStackLayout target,DbRow item)
    {
        target.Add(Ui.Text(item.Text("name")+" · "+ItemCatalog.ItemName(item),15,bold:true));
        foreach(var key in new[]{"itemCode","weight","spec","unitPrice","brand","serialNo","accessory","amount","quotedPrice","appraisalPrice"})
        {
            if(item.Text(key).Length==0 || item.Text("type") is "PROPERTY" or "VEHICLE" && key is "weight" or "spec" or "unitPrice")continue;
            if(key is "amount" or "appraisalPrice" && item.Money(key)==0)continue;
            target.Add(Ui.Spread(Ui.Text(FieldLabels[key],12,Ui.Muted),Ui.Text(item.Text(key),13)));
        }
        AddAttributes(target,item);
        foreach(var photo in MediaFiles.Parse(item.Text("images")))try{target.Add(new Image{Source=MediaFiles.Source(photo),HeightRequest=150,Aspect=Aspect.AspectFit});}catch{ }
        target.Add(Ui.Divider());
    }
    private void AddAttributes(VerticalStackLayout target,DbRow row)
    {
        if(string.IsNullOrWhiteSpace(row.Text("extraAttributes")))return;
        var labels=new Dictionary<string,string>(ItemCatalog.AttributeLabels);
        var config=service.Db.Query("SELECT attributes FROM PawnItemTypeRate WHERE itemType=@p0",row.Text("type")).FirstOrDefault()?.Text("attributes");
        if(!string.IsNullOrWhiteSpace(config))try
        {
            using var definition=JsonDocument.Parse(config);
            if(definition.RootElement.ValueKind==JsonValueKind.Array)foreach(var attr in definition.RootElement.EnumerateArray())
                if(attr.ValueKind==JsonValueKind.Object&&attr.TryGetProperty("key",out var key))labels[key.ToString()]=attr.TryGetProperty("label",out var label)?label.ToString():key.ToString();
        }catch(JsonException){}
        try
        {
            using var values=JsonDocument.Parse(row.Text("extraAttributes"));if(values.RootElement.ValueKind!=JsonValueKind.Object)return;
            foreach(var value in values.RootElement.EnumerateObject())if(value.Value.ValueKind!=JsonValueKind.Null&&value.Value.ToString().Length>0)
                target.Add(Ui.Spread(Ui.Text(labels.GetValueOrDefault(value.Name,value.Name),12,Ui.Muted),Ui.Text(value.Value.ToString(),13)));
        }catch(JsonException){}
    }
    public static readonly Dictionary<string,string> FieldLabels=new()
    {
        ["majorClass"]="财务大类",["detailClass"]="财务细类",["saleAmount"]="未归还设备售价",
        ["material"]="物品材质",["unitPrice"]="入库单价(元/克)",["itemCode"]="物品编码",["expectedAmount"]="客户期望金额",["serviceFeeMode"]="寄卖服务费方式",["serviceFeeValue"]="寄卖服务费",["storageFee"]="保管费(元)",
        ["name"]="名称",["customerName"]="客户姓名",["customerPhone"]="联系电话",["phone"]="联系电话",["gender"]="性别",["idCard"]="证件号码",["address"]="地址",["type"]="类型",["creditLevel"]="信用等级",["isBlacklist"]="黑名单",["tags"]="标签",["itemType"]="物品类型",["itemName"]="物品名称",["principal"]="当金",["appraisalPrice"]="估价",["weight"]="重量(克)",["spec"]="规格 / 成色",["brand"]="品牌",["serialNo"]="序列号",["accessory"]="附件",["monthlyRate"]="月利率(%)",["feeRate"]="综合费率(%)",["storageFeeRate"]="保管费率(%)",["storageFixedFee"]="固定保管费",["fixedInterest"]="固定利息",["pawnDate"]="开当日期",["dueDate"]="到期日期",["status"]="状态",["feeChargeMode"]="收费方式",["remark"]="备注",["amount"]="金额",["cost"]="成本",["profit"]="利润",["quotedPrice"]="客户报价",["dealDate"]="成交日期",["payMethod"]="付款方式",["occurDate"]="发生日期",["category"]="财务分类",["listedPrice"]="销售标价",["soldAt"]="售出日期",["startDate"]="开始日期",["endDate"]="结束日期",["commission"]="佣金",["deposit"]="押金",["images"]="物品照片",["contractImages"]="合同照片",["idCardImages"]="证件照片",["createdAt"]="创建时间",["updatedAt"]="更新时间",["action"]="操作",["targetType"]="记录类型",["targetName"]="记录名称",["detail"]="操作内容",["role"]="角色",["baseSalary"]="基本工资",["content"]="模板内容"
    };
}