Просмотр исходного кода

fix: 统一前端金额显示单位为元,数据流转保持分为单位

订单表单、设备远程控制、平台设备配置等页面的金额输入/显示由分改为元,
表单加载时自动分→元转换,提交时自动元→分转换,数据流转层不变。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline 1 день назад
Родитель
Сommit
2fbcf822c7

+ 26 - 17
admin-web/src/views/admin/ordering/dialog.vue

@@ -20,26 +20,26 @@
           size="default"
           label-width="100px"
           class="mt5">
-        <el-form-item label="消费总额,等于各单项费用之和(单位分)" prop="amount">
+        <el-form-item label="消费总额,等于各单项费用之和()" prop="amount">
           <el-input
               v-model="state.ruleForm.amount"
-              placeholder="消费总额,等于各单项费用之和(单位分)"
+              placeholder="消费总额,等于各单项费用之和()"
               clearable
               class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="应收金额,如果大于预付金额,则限制为预付金额并关机,否则等于消费总金额(单位分)" prop="amountReceivable">
+        <el-form-item label="应收金额,如果大于预付金额,则限制为预付金额并关机,否则等于消费总金额()" prop="amountReceivable">
           <el-input
               v-model="state.ruleForm.amountReceivable"
-              placeholder="应收金额,如果大于预付金额,则限制为预付金额并关机,否则等于消费总金额(单位分)"
+              placeholder="应收金额,如果大于预付金额,则限制为预付金额并关机,否则等于消费总金额()"
               clearable
               class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="实收金额等于应收金额乘会员折扣(单位分)" prop="amountReceived">
+        <el-form-item label="实收金额等于应收金额乘会员折扣()" prop="amountReceived">
           <el-input
               v-model="state.ruleForm.amountReceived"
-              placeholder="实收金额等于应收金额乘会员折扣(单位分)"
+              placeholder="实收金额等于应收金额乘会员折扣()"
               clearable
               class="wd350">
           </el-input>
@@ -92,10 +92,10 @@
               class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="投币的累计金额(仅限刷卡订单,单位分)" prop="coinMoney">
+        <el-form-item label="投币的累计金额(仅限刷卡订单,)" prop="coinMoney">
           <el-input
               v-model="state.ruleForm.coinMoney"
-              placeholder="投币的累计金额(仅限刷卡订单,单位分)"
+              placeholder="投币的累计金额(仅限刷卡订单,)"
               clearable
               class="wd350">
           </el-input>
@@ -116,10 +116,10 @@
               class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="费用明细:name 名称 price 单价(单位分) seconds 时长(单位秒) amount 费用(单位分) space⻋位或场地,water清水,foam泡沫,cleaner吸尘,tap水龙头,user_ext用户扩展,消毒或吹干等功能,coat镀膜,blow吹气" prop="detail">
+        <el-form-item label="费用明细:name 名称 price 单价(元) seconds 时长(单位秒) amount 费用(元) space⻋位或场地,water清水,foam泡沫,cleaner吸尘,tap水龙头,user_ext用户扩展,消毒或吹干等功能,coat镀膜,blow吹气" prop="detail">
           <el-input
               v-model="state.ruleForm.detail"
-              placeholder="费用明细:name 名称 price 单价(单位分) seconds 时长(单位秒) amount 费用(单位分) space⻋位或场地,water清水,foam泡沫,cleaner吸尘,tap水龙头,user_ext用户扩展,消毒或吹干等功能,coat镀膜,blow吹气"
+              placeholder="费用明细:name 名称 price 单价(元) seconds 时长(单位秒) amount 费用(元) space⻋位或场地,water清水,foam泡沫,cleaner吸尘,tap水龙头,user_ext用户扩展,消毒或吹干等功能,coat镀膜,blow吹气"
               clearable
               class="wd350">
           </el-input>
@@ -132,18 +132,18 @@
               class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="优惠金额()" prop="discountAmount">
+        <el-form-item label="优惠金额()" prop="discountAmount">
           <el-input
               v-model="state.ruleForm.discountAmount"
-              placeholder="优惠金额()"
+              placeholder="优惠金额()"
               clearable
               class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="优惠金额等于消费总额减去实收金额(单位分)" prop="discountMoney">
+        <el-form-item label="优惠金额等于消费总额减去实收金额()" prop="discountMoney">
           <el-input
               v-model="state.ruleForm.discountMoney"
-              placeholder="优惠金额等于消费总额减去实收金额(单位分)"
+              placeholder="优惠金额等于消费总额减去实收金额()"
               clearable
               class="wd350">
           </el-input>
@@ -244,10 +244,10 @@
               class="wd350">
           </el-input>
         </el-form-item>
-        <el-form-item label="本次开机的预付金额(单位分,本次开机最大消费金额限制)" prop="prepayMoney">
+        <el-form-item label="本次开机的预付金额(,本次开机最大消费金额限制)" prop="prepayMoney">
           <el-input
               v-model="state.ruleForm.prepayMoney"
-              placeholder="本次开机的预付金额(单位分,本次开机最大消费金额限制)"
+              placeholder="本次开机的预付金额(,本次开机最大消费金额限制)"
               clearable
               class="wd350">
           </el-input>
@@ -359,8 +359,12 @@ const onSubmit = () => {
   formRef.value.validate((v: boolean) => {
     if (v) {
       state.btnLoading = true;
+      const ruleForm = { ...state.ruleForm };
+      moneyFields.forEach(f => {
+        if (ruleForm[f] != null && ruleForm[f] !== '') ruleForm[f] = Math.round(Number(ruleForm[f]) * 100);
+      });
       const url = !!state.ruleForm.id ? "washOrder/modify" : "washOrder/add"
-      $body(url, state.ruleForm).then(() => {
+      $body(url, ruleForm).then(() => {
         state.btnLoading = false;
         Msg.message('操作成功');
         //console.log('submit!')
@@ -378,9 +382,14 @@ const handleFormChange = (formData: any) => {
   //console.log(formData)
 }
 
+const moneyFields = ['amount', 'amountReceivable', 'amountReceived', 'cardBalance', 'coinMoney', 'discountAmount', 'discountMoney', 'prepayMoney'];
+
 // 初始化数据
 const loadData = (id: number) => {
   $get(`washOrder/detail/${id}`).then((res: any) => {
+    moneyFields.forEach(f => {
+      if (res[f] != null) res[f] = (res[f] / 100).toFixed(2);
+    });
     state.ruleForm = res;
   })
 }

+ 37 - 19
admin-web/src/views/admin/platform/deviceConfig/dialog.vue

@@ -266,74 +266,83 @@
         </el-form-item>
         <div class="sub-group-bottom">价格参数</div>
 
-        <el-form-item label="吹气单价(/分钟)" prop="priceBlow" class="wd300">
+        <el-form-item label="吹气单价(/分钟)" prop="priceBlow" class="wd300">
           <el-input-number
               v-model="state.ruleForm.priceBlow"
-              placeholder="吹气单价(分/分钟)"
+              placeholder="吹气单价(元/分钟)"
+              :min="0" :precision="2" :step="0.1"
               clearable
               class="w100">
           </el-input-number>
         </el-form-item>
-        <el-form-item label="吸尘单价(/分钟)" prop="priceCleaner" class="wd300">
+        <el-form-item label="吸尘单价(/分钟)" prop="priceCleaner" class="wd300">
           <el-input-number
               v-model="state.ruleForm.priceCleaner"
-              placeholder="吸尘单价(分/分钟)"
+              placeholder="吸尘单价(元/分钟)"
+              :min="0" :precision="2" :step="0.1"
               clearable
               class="w100">
           </el-input-number>
         </el-form-item>
-        <el-form-item label="镀膜单价(/分钟)" prop="priceCoat" class="wd300">
+        <el-form-item label="镀膜单价(/分钟)" prop="priceCoat" class="wd300">
           <el-input-number
               v-model="state.ruleForm.priceCoat"
-              placeholder="镀膜单价(分/分钟)"
+              placeholder="镀膜单价(元/分钟)"
+              :min="0" :precision="2" :step="0.1"
               clearable
               class="w100">
           </el-input-number>
         </el-form-item>
-        <el-form-item label="泡沫单价(/分钟)" prop="priceFoam" class="wd300">
+        <el-form-item label="泡沫单价(/分钟)" prop="priceFoam" class="wd300">
           <el-input-number
               v-model="state.ruleForm.priceFoam"
-              placeholder="泡沫单价(分/分钟)"
+              placeholder="泡沫单价(元/分钟)"
+              :min="0" :precision="2" :step="0.1"
               clearable
               class="w100">
           </el-input-number>
         </el-form-item>
-        <el-form-item label="场地费单价(/分钟)" prop="priceSpace" class="wd300">
+        <el-form-item label="场地费单价(/分钟)" prop="priceSpace" class="wd300">
           <el-input-number
               v-model="state.ruleForm.priceSpace"
-              placeholder="场地费单价(分/分钟)"
+              placeholder="场地费单价(元/分钟)"
+              :min="0" :precision="2" :step="0.1"
               clearable
               class="w100">
           </el-input-number>
         </el-form-item>
-        <el-form-item label="洗手单价(/分钟)" prop="priceTap" class="wd300">
+        <el-form-item label="洗手单价(/分钟)" prop="priceTap" class="wd300">
           <el-input-number
               v-model="state.ruleForm.priceTap"
-              placeholder="洗手单价(分/分钟)"
+              placeholder="洗手单价(元/分钟)"
+              :min="0" :precision="2" :step="0.1"
               clearable
               class="w100">
           </el-input-number>
         </el-form-item>
-        <el-form-item label="扩展项目单价(/分钟)" prop="priceUserExt" class="wd300">
+        <el-form-item label="扩展项目单价(/分钟)" prop="priceUserExt" class="wd300">
           <el-input-number
               v-model="state.ruleForm.priceUserExt"
-              placeholder="扩展项目单价(分/分钟)"
+              placeholder="扩展项目单价(元/分钟)"
+              :min="0" :precision="2" :step="0.1"
               clearable
               class="w100">
           </el-input-number>
         </el-form-item>
-        <el-form-item label="清水单价(/分钟)" prop="priceWater" class="wd300">
+        <el-form-item label="清水单价(/分钟)" prop="priceWater" class="wd300">
           <el-input-number
               v-model="state.ruleForm.priceWater"
-              placeholder="清水单价(分/分钟)"
+              placeholder="清水单价(元/分钟)"
+              :min="0" :precision="2" :step="0.1"
               clearable
               class="w100">
           </el-input-number>
         </el-form-item>
-        <el-form-item label="快速开机金额" prop="quickOpenMoney" class="w100">
+        <el-form-item label="快速开机金额(元)" prop="quickOpenMoney" class="w100">
           <el-input-number
               v-model="state.ruleForm.quickOpenMoney"
-              placeholder="快速开机金额,按机箱内部的维护按键直接开机(设置为0可以关闭这个功能)"
+              placeholder="快速开机金额(元),按机箱内部的维护按键直接开机(设置为0可以关闭这个功能)"
+              :min="0" :precision="2" :step="1"
               clearable
               class="w100">
           </el-input-number>
@@ -408,13 +417,19 @@ const onClose = () => {
 const onCancel = () => {
   onClose();
 };
+const moneyFields = ['priceBlow', 'priceCleaner', 'priceCoat', 'priceFoam', 'priceSpace', 'priceTap', 'priceUserExt', 'priceWater', 'quickOpenMoney'];
+
 // 提交
 const onSubmit = () => {
   formRef.value.validate((v: boolean) => {
     if (v) {
       state.btnLoading = true;
+      const ruleForm = { ...state.ruleForm };
+      moneyFields.forEach(f => {
+        if (ruleForm[f] != null && ruleForm[f] !== '') ruleForm[f] = Math.round(Number(ruleForm[f]) * 100);
+      });
       const url = !!state.ruleForm.id ? "device-config/modify" : "device-config/add"
-      $body(url, state.ruleForm).then(() => {
+      $body(url, ruleForm).then(() => {
         state.btnLoading = false;
         Msg.message('操作成功');
         console.log('submit!')
@@ -435,6 +450,9 @@ const handleFormChange = (formData: any) => {
 // 初始化数据
 const loadData = (shortId: string) => {
   $post(`device-config/${shortId}`).then((res: any) => {
+    moneyFields.forEach(f => {
+      if (res[f] != null) res[f] = (res[f] / 100).toFixed(2);
+    });
     state.ruleForm = res;
   })
 }

+ 40 - 22
admin-web/src/views/admin/station/device/remote.vue

@@ -215,7 +215,7 @@
           <div class="func-btn" v-for="fn in functionButtons" :key="fn.key" @click="editPrice(fn)">
             <span class="func-icon">{{ fn.icon }}</span>
             <span class="func-name">{{ fn.name }}</span>
-            <span class="func-price">{{ fn.price != null ? (fn.price / 100).toFixed(2) + '元/分' : '--' }}</span>
+            <span class="func-price">{{ fn.price != null ? (fn.price / 100).toFixed(2) + '元/分' : '--' }}</span>
           </div>
         </div>
 
@@ -253,29 +253,29 @@
         <div class="config-editor" v-if="state.showConfigEditor">
           <div class="config-title">设备配置编辑</div>
           <el-form :model="state.configForm" label-width="140px" size="small" inline>
-            <el-form-item label="清水单价(分/分)">
-              <el-input-number v-model="state.configForm.priceWater" :min="0" size="small" controls-position="right"/>
+            <el-form-item label="清水单价(元/分钟)">
+              <el-input-number v-model="state.configForm.priceWater" :min="0" :precision="2" :step="0.1" size="small" controls-position="right"/>
             </el-form-item>
-            <el-form-item label="泡沫单价(分/分)">
-              <el-input-number v-model="state.configForm.priceFoam" :min="0" size="small" controls-position="right"/>
+            <el-form-item label="泡沫单价(元/分钟)">
+              <el-input-number v-model="state.configForm.priceFoam" :min="0" :precision="2" :step="0.1" size="small" controls-position="right"/>
             </el-form-item>
-            <el-form-item label="吸尘单价(分/分)">
-              <el-input-number v-model="state.configForm.priceCleaner" :min="0" size="small" controls-position="right"/>
+            <el-form-item label="吸尘单价(元/分钟)">
+              <el-input-number v-model="state.configForm.priceCleaner" :min="0" :precision="2" :step="0.1" size="small" controls-position="right"/>
             </el-form-item>
-            <el-form-item label="洗手单价(分/分)">
-              <el-input-number v-model="state.configForm.priceTap" :min="0" size="small" controls-position="right"/>
+            <el-form-item label="洗手单价(元/分钟)">
+              <el-input-number v-model="state.configForm.priceTap" :min="0" :precision="2" :step="0.1" size="small" controls-position="right"/>
             </el-form-item>
-            <el-form-item label="扩展单价(分/分)">
-              <el-input-number v-model="state.configForm.priceUserExt" :min="0" size="small" controls-position="right"/>
+            <el-form-item label="扩展单价(元/分钟)">
+              <el-input-number v-model="state.configForm.priceUserExt" :min="0" :precision="2" :step="0.1" size="small" controls-position="right"/>
             </el-form-item>
-            <el-form-item label="镀膜单价(分/分)">
-              <el-input-number v-model="state.configForm.priceCoat" :min="0" size="small" controls-position="right"/>
+            <el-form-item label="镀膜单价(元/分钟)">
+              <el-input-number v-model="state.configForm.priceCoat" :min="0" :precision="2" :step="0.1" size="small" controls-position="right"/>
             </el-form-item>
-            <el-form-item label="吹气单价(分/分)">
-              <el-input-number v-model="state.configForm.priceBlow" :min="0" size="small" controls-position="right"/>
+            <el-form-item label="吹气单价(元/分钟)">
+              <el-input-number v-model="state.configForm.priceBlow" :min="0" :precision="2" :step="0.1" size="small" controls-position="right"/>
             </el-form-item>
-            <el-form-item label="场地费(分/分)">
-              <el-input-number v-model="state.configForm.priceSpace" :min="0" size="small" controls-position="right"/>
+            <el-form-item label="场地费(元/分钟)">
+              <el-input-number v-model="state.configForm.priceSpace" :min="0" :precision="2" :step="0.1" size="small" controls-position="right"/>
             </el-form-item>
             <el-form-item label="空闲超时(秒)">
               <el-input-number v-model="state.configForm.idleTimeout" :min="0" size="small" controls-position="right"/>
@@ -394,6 +394,8 @@ const functionButtons = [
   {key: 'priceSpace',     name: '场地费', icon: '🅿️', price: null as number | null},
 ];
 
+const priceKeys = functionButtons.map(f => f.key);
+
 const statusClass = computed(() => {
   const map: Record<string, string> = {busy: 'busy', idle: 'idle', init: 'init', fault: 'fault', maintenance: 'maintenance', sleep: 'sleep'};
   return map[state.deviceState] || '';
@@ -448,10 +450,10 @@ const loadDeviceState = async () => {
   // 自动加载设备配置,填充功能按钮价格
   try {
     const config: any = await api('readConfig');
-    state.configForm = {...config};
     for (const fn of functionButtons) {
       fn.price = config?.[fn.key] ?? null;
     }
+    state.configForm = fenToYuanConfig(config);
   } catch (e) {
     // 配置加载失败不影响面板使用,功能按钮显示 "--"
     for (const fn of functionButtons) {
@@ -469,11 +471,11 @@ const handleReadConfig = async () => {
   state.loading = true;
   try {
     const res: any = await api('readConfig');
-    state.configForm = {...res};
-    // 同步价格到功能按钮
+    // 同步价格到功能按钮(保持fen)
     for (const fn of functionButtons) {
       fn.price = res?.[fn.key] ?? null;
     }
+    state.configForm = fenToYuanConfig(res);
     state.showConfigEditor = true;
     Msg.message('配置读取成功', 'success');
   } catch (e) {
@@ -486,10 +488,10 @@ const handleReadConfig = async () => {
 const handleWriteConfig = async () => {
   state.loading = true;
   try {
-    await api('writeConfig', {config: state.configForm});
+    await api('writeConfig', {config: yuanToFenConfig(state.configForm)});
     // 同步更新按钮显示的价格
     for (const fn of functionButtons) {
-      fn.price = state.configForm[fn.key] ?? null;
+      fn.price = Math.round(state.configForm[fn.key] * 100);
     }
     Msg.message('配置写入成功', 'success');
   } catch (e) {
@@ -598,5 +600,21 @@ const handleForceCloseOrder = () => {
   });
 };
 
+const fenToYuanConfig = (config: any) => {
+  const c = { ...config };
+  priceKeys.forEach(k => {
+    if (c[k] != null) c[k] = parseFloat((c[k] / 100).toFixed(2));
+  });
+  return c;
+};
+
+const yuanToFenConfig = (config: any) => {
+  const c = { ...config };
+  priceKeys.forEach(k => {
+    if (c[k] != null) c[k] = Math.round(c[k] * 100);
+  });
+  return c;
+};
+
 defineExpose({open});
 </script>