From c8f0ff5f17a68c17bd3bb428e57a84fcc8a48f65 Mon Sep 17 00:00:00 2001 From: “wangming” <“wangming@antissoft.com”> Date: Tue, 17 Mar 2026 20:54:51 +0800 Subject: [PATCH] Refactor LqCooperationCostService to streamline export functionality, ensuring all data is exported without pagination. Enhance error handling for total amount validation to support negative values and various formats. Add a new method for parsing decimal values, accommodating accounting formats. Update documentation for clarity on export parameters and import requirements. --- netcore/src/Modularity/Extend/NCC.Extend/LqCooperationCostService.cs | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------------- netcore/src/Modularity/Message/NCC.Message.Entitys/NCC.Message.Entitys.csproj | 7 +++++-- store-pc/src/components/ConsumeDialog.vue | 30 ++++++++++++++++++++++++++++++ store-pc/src/components/EmployeeScheduleDialog.vue | 202 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- store-pc/src/components/booking-consume-detail-dialog.vue | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ store-pc/src/components/booking-consume-dialog.vue | 922 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ store-pc/src/components/room-usage-dialog.vue | 268 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ store-pc/src/views/dashboard/index.vue | 19 +++++++++++++++++-- 8 files changed, 1731 insertions(+), 20 deletions(-) create mode 100644 store-pc/src/components/booking-consume-detail-dialog.vue create mode 100644 store-pc/src/components/booking-consume-dialog.vue create mode 100644 store-pc/src/components/room-usage-dialog.vue diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqCooperationCostService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqCooperationCostService.cs index 74e9817..32c17d9 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqCooperationCostService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqCooperationCostService.cs @@ -25,6 +25,7 @@ using NCC.ClayObject; using NCC.Common.Const; using NCC.Extend.Entitys.Enum; using Microsoft.AspNetCore.Http; +using System.Globalization; using System.IO; using System.Data; @@ -288,22 +289,17 @@ namespace NCC.Extend.LqCooperationCost /// /// 导出合作成本表 /// + /// + /// 未传入任何筛选参数时,默认导出全部数据;传入 storeId、storeName、year、month 时按条件筛选导出。 + /// /// 请求参数 /// [HttpGet("Actions/Export")] public async Task Export([FromQuery] LqCooperationCostListQueryInput input) { var userInfo = await _userManager.GetUserInfo(); - var exportData = new List(); - if (input.dataType == 0) - { - var data = Clay.Object(await this.GetList(input)); - exportData = data.Solidify>().list; - } - else - { - exportData = await this.GetNoPagingList(input); - } + // 导出时统一使用无分页列表:未传参数则导出全部,有参数则按条件筛选 + var exportData = await this.GetNoPagingList(input); List paramList = "[{\"value\":\"门店名称\",\"field\":\"storeName\"},{\"value\":\"年份\",\"field\":\"year\"},{\"value\":\"月份\",\"field\":\"month\"},{\"value\":\"合计金额\",\"field\":\"totalAmount\"},{\"value\":\"成本类型\",\"field\":\"costType\"},{\"value\":\"备注说明\",\"field\":\"remarks\"},{\"value\":\"创建人\",\"field\":\"createUser\"},{\"value\":\"创建时间\",\"field\":\"createTime\"},]".ToList(); ExcelConfig excelconfig = new ExcelConfig(); excelconfig.FileName = "合作成本表.xls"; @@ -402,6 +398,9 @@ namespace NCC.Extend.LqCooperationCost /// 第一行为标题行:门店名称、年份、月份、合计金额、成本类型、备注说明 /// 从第二行开始为数据行 /// + /// 合计金额支持正数和负数,负数可用于冲减、退款等场景; + /// 支持格式:-100、-100.50、会计格式(100)等 + /// /// 注意:导入时通过门店名称查找门店ID,不需要填写门店ID /// /// 示例请求: @@ -511,10 +510,17 @@ namespace NCC.Extend.LqCooperationCost continue; } - // 验证合计金额 - if (string.IsNullOrEmpty(totalAmountText) || !decimal.TryParse(totalAmountText, out decimal totalAmount)) + // 验证合计金额(支持正数和负数,如冲减、退款等场景) + if (string.IsNullOrEmpty(totalAmountText)) + { + failMessages.Add($"第{i + 1}行:合计金额不能为空"); + failCount++; + continue; + } + + if (!TryParseDecimalAllowNegative(totalAmountText, out decimal totalAmount)) { - failMessages.Add($"第{i + 1}行:合计金额格式错误(应为数字)"); + failMessages.Add($"第{i + 1}行:合计金额格式错误(应为数字,支持负数如-100或会计格式(100))"); failCount++; continue; } @@ -616,6 +622,41 @@ namespace NCC.Extend.LqCooperationCost throw NCCException.Oh($"导入失败:{ex.Message}"); } } + + /// + /// 解析合计金额字符串,支持正数和负数 + /// + /// 待解析的字符串 + /// 解析结果 + /// 是否解析成功 + /// + /// 支持格式:-100、-100.50、会计格式(100)或(100)、千分位1,234.56等 + /// + private static bool TryParseDecimalAllowNegative(string text, out decimal result) + { + result = 0; + if (string.IsNullOrWhiteSpace(text)) return false; + + var cleaned = text.Trim() + .Replace(",", "") + .Replace(",", "") + .Replace("¥", "") + .Replace("$", "") + .Replace("元", "") + .Replace(" ", ""); + + // 会计格式:(100) 或 (100)表示负数 + if (cleaned.StartsWith("(") && cleaned.EndsWith(")")) + { + cleaned = "-" + cleaned.Substring(1, cleaned.Length - 2).Trim(); + } + else if (cleaned.StartsWith("(") && cleaned.EndsWith(")")) + { + cleaned = "-" + cleaned.Substring(1, cleaned.Length - 2).Trim(); + } + + return decimal.TryParse(cleaned, NumberStyles.Number, CultureInfo.InvariantCulture, out result); + } } } diff --git a/netcore/src/Modularity/Message/NCC.Message.Entitys/NCC.Message.Entitys.csproj b/netcore/src/Modularity/Message/NCC.Message.Entitys/NCC.Message.Entitys.csproj index c94d0e7..c9bee1e 100644 --- a/netcore/src/Modularity/Message/NCC.Message.Entitys/NCC.Message.Entitys.csproj +++ b/netcore/src/Modularity/Message/NCC.Message.Entitys/NCC.Message.Entitys.csproj @@ -1,11 +1,14 @@ - + net6.0 + + bin\Debug\$(AssemblyName).xml + - D:\wesley\project\git\antis-food-alliance\netcore\src\Modularity\Message\NCC.Message.Entitys\NCC.Message.Entitys.xml + bin\Release\$(AssemblyName).xml diff --git a/store-pc/src/components/ConsumeDialog.vue b/store-pc/src/components/ConsumeDialog.vue index bc7a731..9bc9364 100644 --- a/store-pc/src/components/ConsumeDialog.vue +++ b/store-pc/src/components/ConsumeDialog.vue @@ -372,7 +372,37 @@ export default { this.form.memberName = this.prefill.name || '' this.loadMemberItems(this.prefill.memberId) } + if (this.prefill && this.prefill.consumeDate) { + const d = this.prefill.consumeDate instanceof Date ? this.prefill.consumeDate : new Date(this.prefill.consumeDate) + if (!Number.isNaN(d.getTime())) this.form.consumeDate = d + } + if (this.prefill && this.prefill.remark) { + this.form.remark = this.prefill.remark + } this.$nextTick(() => { + // 预填品项(用于“预约消耗单 -> 转消耗”闭环,mock 预填即可) + const preItems = (this.prefill && Array.isArray(this.prefill.items)) ? this.prefill.items : null + if (preItems && preItems.length) { + this.form.items = preItems.map(pi => { + const it = this.createEmptyItem() + it.projectId = pi.projectId || '' + it.count = pi.count || 1 + return it + }) + // 触发品项信息填充与业绩分配 + this.form.items.forEach((_, idx) => { + if (this.form.items[idx].projectId) this.onProjectChange(idx) + }) + } + + // 预填健康师(把 therapistIds 映射到每个品项的 workers) + const tids = (this.prefill && Array.isArray(this.prefill.therapistIds)) ? this.prefill.therapistIds : null + if (tids && tids.length) { + this.form.items.forEach((item, idx) => { + item.workers = tids.map(tid => ({ workerId: tid, performance: '', laborCost: '', count: '' })) + this.redistributeWorkers(idx) + }) + } this.$refs.form && this.$refs.form.clearValidate() }) }, diff --git a/store-pc/src/components/EmployeeScheduleDialog.vue b/store-pc/src/components/EmployeeScheduleDialog.vue index d15e482..9064abb 100644 --- a/store-pc/src/components/EmployeeScheduleDialog.vue +++ b/store-pc/src/components/EmployeeScheduleDialog.vue @@ -103,7 +103,7 @@ - + + + + + + + @@ -935,6 +1097,40 @@ export default { .slot--resize-start { cursor: w-resize; } .slot--resize-end { cursor: e-resize; } +/* 预约消耗单块:不同状态 + 同单高亮 */ +.slot--preconsume { + position: relative; + background: rgba(37, 99, 235, 0.42); + &:hover { background: rgba(37, 99, 235, 0.6); } +} +.slot--preconsume-booked { } +.slot--preconsume-serving { + background: rgba(249, 115, 22, 0.55); + &:hover { background: rgba(249, 115, 22, 0.7); } +} +.slot--preconsume-converted { + background: rgba(34, 197, 94, 0.5); + &:hover { background: rgba(34, 197, 94, 0.7); } +} +.slot--preconsume-cancelled { + background: rgba(239, 68, 68, 0.45); + &:hover { background: rgba(239, 68, 68, 0.6); } +} + +.slot--preconsume-color-blue { box-shadow: inset 0 -2px 0 rgba(37, 99, 235, 0.65); } +.slot--preconsume-color-green { box-shadow: inset 0 -2px 0 rgba(34, 197, 94, 0.7); } +.slot--preconsume-color-orange { box-shadow: inset 0 -2px 0 rgba(249, 115, 22, 0.75); } +.slot--preconsume-color-purple { box-shadow: inset 0 -2px 0 rgba(139, 92, 246, 0.75); } +.slot--preconsume-color-gray { box-shadow: inset 0 -2px 0 rgba(148, 163, 184, 0.8); } + +.slot--same-active { + outline: 2px solid rgba(17, 24, 39, 0.25); + z-index: 1; +} +.slot--dimmed { + opacity: 0.35; +} + /* 预约详情弹窗 - 与主弹窗风格统一 */ ::v-deep .schedule-detail-dialog { border-radius: 20px; diff --git a/store-pc/src/components/booking-consume-detail-dialog.vue b/store-pc/src/components/booking-consume-detail-dialog.vue new file mode 100644 index 0000000..97a1b1f --- /dev/null +++ b/store-pc/src/components/booking-consume-detail-dialog.vue @@ -0,0 +1,236 @@ + + + + + + diff --git a/store-pc/src/components/booking-consume-dialog.vue b/store-pc/src/components/booking-consume-dialog.vue new file mode 100644 index 0000000..c840b78 --- /dev/null +++ b/store-pc/src/components/booking-consume-dialog.vue @@ -0,0 +1,922 @@ + + + + + + diff --git a/store-pc/src/components/room-usage-dialog.vue b/store-pc/src/components/room-usage-dialog.vue new file mode 100644 index 0000000..b57bb82 --- /dev/null +++ b/store-pc/src/components/room-usage-dialog.vue @@ -0,0 +1,268 @@ + + + + + + diff --git a/store-pc/src/views/dashboard/index.vue b/store-pc/src/views/dashboard/index.vue index 695fdc0..0d954f6 100644 --- a/store-pc/src/views/dashboard/index.vue +++ b/store-pc/src/views/dashboard/index.vue @@ -371,6 +371,10 @@ @action="handleMemberAction" /> + @@ -433,6 +437,7 @@ import TuokeLeadDialog from '@/components/TuokeLeadDialog.vue' import InviteAddDialog from '@/components/InviteAddDialog.vue' import CompanyCalendarDialog from '@/components/CompanyCalendarDialog.vue' import BookingDialog from '@/components/BookingDialog.vue' +import BookingConsumeDialog from '@/components/booking-consume-dialog.vue' import BillingDialog from '@/components/BillingDialog.vue' import ConsumeDialog from '@/components/ConsumeDialog.vue' import RefundDialog from '@/components/RefundDialog.vue' @@ -452,6 +457,7 @@ export default { InviteAddDialog, CompanyCalendarDialog, BookingDialog, + BookingConsumeDialog, BillingDialog, ConsumeDialog, RefundDialog, @@ -797,6 +803,7 @@ export default { name: '', phone: '' }, + bookingConsumeDialogVisible: false, billingDialogVisible: false, billingPrefill: {}, consumeDialogVisible: false, @@ -1025,8 +1032,7 @@ export default { return } if (module.key === 'booking') { - this.bookingPrefill = { name: '', phone: '' } - this.bookingDialogVisible = true + this.bookingConsumeDialogVisible = true return } if (module.key === 'order') { @@ -1252,6 +1258,15 @@ export default { } this.bookingDialogVisible = true }, + handlePreConsumeBookingSaved(payload) { + // mock:新建预约消耗单后,直接打开排班便于查看时间块 + this.$message.success('预约消耗单已保存') + this.bookingConsumeDialogVisible = false + this.$store.commit('SET_SCHEDULE_DIALOG', true) + this.$store.commit('SET_SCHEDULE_DIALOG_MODE', 'view') + // payload 可按需用于后续联动(例如定位到某天/某单) + void payload + }, handleQuickBilling(item) { this.billingPrefill = { name: item.name, -- libgit2 0.21.4