skyline 1 день назад
Родитель
Сommit
83c2466177

+ 32 - 0
admin-mp/src/pages/device/detail.vue

@@ -56,6 +56,12 @@
           <text class="item-label">是否有泡沫</text>
           <text class="item-label">是否有泡沫</text>
           <text class="item-value">{{ fmtDictName('yes_no', deviceDetail.hasFoam) }}</text>
           <text class="item-value">{{ fmtDictName('yes_no', deviceDetail.hasFoam) }}</text>
         </view>
         </view>
+        <view class="info-item">
+          <text class="item-label">是否支持PA壶</text>
+          <view class="item-value pa-status">
+            <text :class="deviceDetail.hasPa ? 'pa-icon-active' : 'pa-icon-inactive'">PA</text>
+          </view>
+        </view>
         <view class="info-item" v-if="isFault">
         <view class="info-item" v-if="isFault">
           <text class="item-label">故障原因</text>
           <text class="item-label">故障原因</text>
           <text class="item-value item-value-danger">{{ deviceDetail.faultReason || '未知故障' }}</text>
           <text class="item-value item-value-danger">{{ deviceDetail.faultReason || '未知故障' }}</text>
@@ -437,4 +443,30 @@ onMounted(async () => {
   font-size: 28rpx;
   font-size: 28rpx;
   font-weight: 500;
   font-weight: 500;
 }
 }
+
+.pa-status {
+  display: flex;
+  align-items: center;
+  justify-content: flex-end;
+}
+
+.pa-icon-active {
+  display: inline-block;
+  padding: 4rpx 14rpx;
+  background: #C6171E;
+  color: #FFFFFF;
+  border-radius: 8rpx;
+  font-size: 22rpx;
+  font-weight: 700;
+}
+
+.pa-icon-inactive {
+  display: inline-block;
+  padding: 4rpx 14rpx;
+  background: #E0E0E0;
+  color: #999999;
+  border-radius: 8rpx;
+  font-size: 22rpx;
+  font-weight: 700;
+}
 </style>
 </style>

+ 16 - 1
admin-mp/src/pages/device/list.vue

@@ -36,7 +36,10 @@
       >
       >
         <view class="device-header">
         <view class="device-header">
           <view class="device-info">
           <view class="device-info">
-            <text class="device-name">{{ device.name }}</text>
+            <text class="device-name">
+              {{ device.name }}
+              <text v-if="device.hasPa" class="pa-badge-list">PA</text>
+            </text>
             <view class="device-meta">
             <view class="device-meta">
               <text class="device-id">ID: {{ device.shortId }}</text>
               <text class="device-id">ID: {{ device.shortId }}</text>
               <view class="device-status" :style="getDeviceStatusStyle(getDeviceStatusValue(device))">
               <view class="device-status" :style="getDeviceStatusStyle(getDeviceStatusValue(device))">
@@ -450,6 +453,18 @@ const getStatusValue = (filterIndex) => {
   margin-bottom: 10rpx;
   margin-bottom: 10rpx;
 }
 }
 
 
+.pa-badge-list {
+  display: inline-block;
+  margin-left: 10rpx;
+  padding: 2rpx 10rpx;
+  background: #C6171E;
+  color: #FFFFFF;
+  border-radius: 6rpx;
+  font-size: 20rpx;
+  font-weight: 700;
+  vertical-align: middle;
+}
+
 .device-meta {
 .device-meta {
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;

+ 5 - 0
admin-web-new/src/views/admin/station/device-dialog.vue

@@ -20,6 +20,7 @@ const state = reactive({
     status: "",
     status: "",
     hasFoam: "",
     hasFoam: "",
     hasWater: "",
     hasWater: "",
+    hasPa: "",
     temperatureChip: "",
     temperatureChip: "",
     faultReason: "",
     faultReason: "",
     functions: ""
     functions: ""
@@ -39,6 +40,7 @@ const resetForm = () => {
     status: "",
     status: "",
     hasFoam: "",
     hasFoam: "",
     hasWater: "",
     hasWater: "",
+    hasPa: "",
     temperatureChip: "",
     temperatureChip: "",
     faultReason: "",
     faultReason: "",
     functions: ""
     functions: ""
@@ -133,6 +135,9 @@ defineExpose({ open });
       <el-form-item label="是否有水" prop="hasWater">
       <el-form-item label="是否有水" prop="hasWater">
         <ext-d-select v-model="state.ruleForm.hasWater" type="YesNo" placeholder="请选择" />
         <ext-d-select v-model="state.ruleForm.hasWater" type="YesNo" placeholder="请选择" />
       </el-form-item>
       </el-form-item>
+      <el-form-item label="是否支持PA" prop="hasPa">
+        <ext-d-select v-model="state.ruleForm.hasPa" type="YesNo" placeholder="请选择" />
+      </el-form-item>
       <el-form-item label="板载温度" prop="temperatureChip">
       <el-form-item label="板载温度" prop="temperatureChip">
         <el-input v-model="state.ruleForm.temperatureChip" placeholder="板载温度传感器的温度值" />
         <el-input v-model="state.ruleForm.temperatureChip" placeholder="板载温度传感器的温度值" />
       </el-form-item>
       </el-form-item>

+ 3 - 0
admin-web-new/src/views/admin/station/device-remote.vue

@@ -14,6 +14,7 @@ const initState = () => ({
   deviceState: "",
   deviceState: "",
   temperatureChip: null as number | null,
   temperatureChip: null as number | null,
   uptimeMs: "",
   uptimeMs: "",
+  hasPa: false,
   orderInfo: null as any,
   orderInfo: null as any,
   showConfigEditor: false,
   showConfigEditor: false,
   configForm: {} as any,
   configForm: {} as any,
@@ -96,6 +97,7 @@ const loadDeviceState = async () => {
     state.deviceState = res?.device_state?.state || "";
     state.deviceState = res?.device_state?.state || "";
     state.uptimeMs = res?.device_state?.uptime_ms || "";
     state.uptimeMs = res?.device_state?.uptime_ms || "";
     state.temperatureChip = res?.device_state?.temperature_chip ?? null;
     state.temperatureChip = res?.device_state?.temperature_chip ?? null;
+    state.hasPa = res?.device_state?.has_pa === '1' || res?.device_state?.has_pa === 1 || res?.device_state?.has_pa === true;
     state.orderInfo = res?.order_info || null;
     state.orderInfo = res?.order_info || null;
   } catch (e) {
   } catch (e) {
     ElMessage.error("查询设备状态失败");
     ElMessage.error("查询设备状态失败");
@@ -285,6 +287,7 @@ defineExpose({ open });
             </span>
             </span>
             <span><span class="status-label">运行时长</span> <span class="status-value">{{ uptimeDisplay }}</span></span>
             <span><span class="status-label">运行时长</span> <span class="status-value">{{ uptimeDisplay }}</span></span>
             <span><span class="status-label">温度</span> <span class="status-value">{{ temperatureDisplay }}</span></span>
             <span><span class="status-label">温度</span> <span class="status-value">{{ temperatureDisplay }}</span></span>
+            <span><span class="status-label">PA壶</span> <span class="status-value" :style="{color: state.hasPa ? '#00ff88' : '#888'}">{{ state.hasPa ? '支持' : '不支持' }}</span></span>
           </div>
           </div>
           <div>
           <div>
             <el-button size="small" text type="primary" @click="refreshState" :loading="state.loading">
             <el-button size="small" text type="primary" @click="refreshState" :loading="state.loading">

+ 14 - 3
admin-web-new/src/views/admin/station/device.vue

@@ -35,7 +35,8 @@ const state = reactive({
     deviceName: "",
     deviceName: "",
     state: "",
     state: "",
     hasFoam: "",
     hasFoam: "",
-    hasWater: ""
+    hasWater: "",
+    hasPa: ""
   },
   },
   pageQuery: {
   pageQuery: {
     pageNum: 1,
     pageNum: 1,
@@ -57,6 +58,7 @@ const state = reactive({
       { label: "功能", prop: "functions", width: 180 },
       { label: "功能", prop: "functions", width: 180 },
       { label: "是否有泡沫", prop: "hasFoam", width: 100 },
       { label: "是否有泡沫", prop: "hasFoam", width: 100 },
       { label: "是否有水", prop: "hasWater", width: 100 },
       { label: "是否有水", prop: "hasWater", width: 100 },
+      { label: "是否支持PA", prop: "hasPa", width: 100 },
       { label: "创建时间", prop: "createTime", width: 160 },
       { label: "创建时间", prop: "createTime", width: 160 },
       { label: "更新时间", prop: "updateTime", width: 160 }
       { label: "更新时间", prop: "updateTime", width: 160 }
     ]
     ]
@@ -140,7 +142,8 @@ const handleReset = () => {
     deviceName: "",
     deviceName: "",
     state: "",
     state: "",
     hasFoam: "",
     hasFoam: "",
-    hasWater: ""
+    hasWater: "",
+    hasPa: ""
   };
   };
   loadData(true);
   loadData(true);
 };
 };
@@ -291,6 +294,14 @@ const handleRemoteControl = (row: any) => {
             @on-change="handleSearch"
             @on-change="handleSearch"
           />
           />
         </el-form-item>
         </el-form-item>
+        <el-form-item label="是否支持PA">
+          <ExtDSelect
+            v-model="state.formQuery.hasPa"
+            type="YesNo"
+            placeholder="请选择"
+            @on-change="handleSearch"
+          />
+        </el-form-item>
         <el-form-item>
         <el-form-item>
           <el-button
           <el-button
             type="primary"
             type="primary"
@@ -365,7 +376,7 @@ const handleRemoteControl = (row: any) => {
             <template v-else-if="col.prop === 'uptimeMs'">
             <template v-else-if="col.prop === 'uptimeMs'">
               {{ formatDuration(row.uptimeMs) }}
               {{ formatDuration(row.uptimeMs) }}
             </template>
             </template>
-            <template v-else-if="col.prop === 'hasFoam' || col.prop === 'hasWater'">
+            <template v-else-if="col.prop === 'hasFoam' || col.prop === 'hasWater' || col.prop === 'hasPa'">
               <ExtDLabel type="YesNo" :model-value="row[col.prop]" />
               <ExtDLabel type="YesNo" :model-value="row[col.prop]" />
             </template>
             </template>
             <template v-else>
             <template v-else>

+ 3 - 0
admin-web/src/views/admin/station/device/dialog.vue

@@ -66,6 +66,9 @@
           <ext-d-select type="WashDevice.water" v-model="state.ruleForm.hasWater" class="wd200"></ext-d-select>
           <ext-d-select type="WashDevice.water" v-model="state.ruleForm.hasWater" class="wd200"></ext-d-select>
         </el-form-item>
         </el-form-item>
 
 
+        <el-form-item label="是否支持PA" prop="hasPa" class="wd250">
+          <ext-d-select type="YesNo" v-model="state.ruleForm.hasPa" class="wd200"></ext-d-select>
+        </el-form-item>
 
 
         <el-form-item label="板载温度" prop="temperatureChip" class="wd350">
         <el-form-item label="板载温度" prop="temperatureChip" class="wd350">
           <el-input
           <el-input

+ 1 - 0
admin-web/src/views/admin/station/device/index.vue

@@ -160,6 +160,7 @@ const state = reactive({
     {label: '功能', prop: 'functions', width: 180, query: true, type: 'text', resizable: true},
     {label: '功能', prop: 'functions', width: 180, query: true, type: 'text', resizable: true},
     {label: '是否有泡沫', prop: 'hasFoam', width: 120, query: true, type: 'dict', conf: {dict: 'WashDevice.foam'}, resizable: true},
     {label: '是否有泡沫', prop: 'hasFoam', width: 120, query: true, type: 'dict', conf: {dict: 'WashDevice.foam'}, resizable: true},
     {label: '是否有水', prop: 'hasWater', width: 120, query: true, type: 'dict', conf: {dict: 'WashDevice.water'}, resizable: true},
     {label: '是否有水', prop: 'hasWater', width: 120, query: true, type: 'dict', conf: {dict: 'WashDevice.water'}, resizable: true},
+    {label: '是否支持PA', prop: 'hasPa', width: 120, query: true, type: 'dict', conf: {dict: 'YesNo'}, resizable: true},
     // {label: '当前温度', prop: 'temperatureChip', width: 180, query: false, type: 'text', resizable: true},
     // {label: '当前温度', prop: 'temperatureChip', width: 180, query: false, type: 'text', resizable: true},
     {label: '创建时间', prop: 'createTime', query: false, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDateTime(val)}},
     {label: '创建时间', prop: 'createTime', query: false, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDateTime(val)}},
     {label: '更新时间', prop: 'updateTime', query: false, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDateTime(val)}},
     {label: '更新时间', prop: 'updateTime', query: false, sortable: 'custom', type: 'datetime', resizable: true, conf: {format: (val: any) => u.fmt.fmtDateTime(val)}},

+ 3 - 0
admin-web/src/views/admin/station/device/remote.vue

@@ -201,6 +201,7 @@
             </span>
             </span>
             <span><span class="status-label">运行时长</span> <span class="status-value">{{ uptimeDisplay }}</span></span>
             <span><span class="status-label">运行时长</span> <span class="status-value">{{ uptimeDisplay }}</span></span>
             <span><span class="status-label">温度</span> <span class="status-value">{{ temperatureDisplay }}</span></span>
             <span><span class="status-label">温度</span> <span class="status-value">{{ temperatureDisplay }}</span></span>
+            <span><span class="status-label">PA壶</span> <span class="status-value" :style="{color: state.hasPa ? '#00ff88' : '#888'}">{{ state.hasPa ? '支持' : '不支持' }}</span></span>
           </div>
           </div>
           <div>
           <div>
             <el-button size="small" text type="primary" @click="refreshState" :loading="state.loading">
             <el-button size="small" text type="primary" @click="refreshState" :loading="state.loading">
@@ -355,6 +356,7 @@ const initState = () => ({
   deviceState: '',
   deviceState: '',
   temperatureChip: null as number | null,
   temperatureChip: null as number | null,
   uptimeMs: '',
   uptimeMs: '',
+  hasPa: false,
   orderInfo: null as any,
   orderInfo: null as any,
   showConfigEditor: false,
   showConfigEditor: false,
   configForm: {} as any,
   configForm: {} as any,
@@ -437,6 +439,7 @@ const loadDeviceState = async () => {
     state.deviceState = res?.device_state?.state || '';
     state.deviceState = res?.device_state?.state || '';
     state.uptimeMs = res?.device_state?.uptime_ms || '';
     state.uptimeMs = res?.device_state?.uptime_ms || '';
     state.temperatureChip = res?.device_state?.temperature_chip ?? null;
     state.temperatureChip = res?.device_state?.temperature_chip ?? null;
+    state.hasPa = res?.device_state?.has_pa === '1' || res?.device_state?.has_pa === 1 || res?.device_state?.has_pa === true;
     state.orderInfo = res?.order_info || null;
     state.orderInfo = res?.order_info || null;
   } catch (e) {
   } catch (e) {
     Msg.message('查询设备状态失败', 'error');
     Msg.message('查询设备状态失败', 'error');

+ 5 - 0
car-wash-entity/src/main/java/com/kym/entity/WashDevice.java

@@ -72,6 +72,11 @@ public class WashDevice extends BaseEntity {
      */
      */
     private Boolean hasFoam;
     private Boolean hasFoam;
 
 
+    /**
+     * 是否支持PA壶:0不支持,1支持
+     */
+    private Boolean hasPa;
+
     /**
     /**
      * 板载温度传感器的温度值
      * 板载温度传感器的温度值
      */
      */

+ 6 - 0
car-wash-entity/src/main/java/com/kym/entity/awoara/DeviceState.java

@@ -49,6 +49,12 @@ public class DeviceState {
      * 1 表⽰有泡沫
      * 1 表⽰有泡沫
      */
      */
     private String has_foam;
     private String has_foam;
+    /**
+     * 是否支持PA壶
+     * 0 不支持
+     * 1 支持
+     */
+    private String has_pa;
     /**
     /**
      * 板载温度传感器的温度值
      * 板载温度传感器的温度值
      */
      */

+ 5 - 0
car-wash-entity/src/main/java/com/kym/entity/vo/WashDeviceVo.java

@@ -95,6 +95,11 @@ public class WashDeviceVo extends BaseEntity {
      */
      */
     private Boolean hasFoam;
     private Boolean hasFoam;
 
 
+    /**
+     * 是否支持PA壶:0不支持,1支持
+     */
+    private Boolean hasPa;
+
     /**
     /**
      * 板载温度传感器的温度值
      * 板载温度传感器的温度值
      */
      */

+ 3 - 11
car-wash-mp/src/pages-user/faq/index.vue

@@ -15,36 +15,28 @@ import {reactive} from "vue";
 const guideContent = [
 const guideContent = [
   {
   {
     question: "如何使用自助洗车机?",
     question: "如何使用自助洗车机?",
-    answer: "<p>使用Yeswash自助洗车非常简单,只需三步:</p><p><strong>1. 扫码启动</strong> — 打开小程序,扫描洗车机上的二维码,选择洗车套餐并支付。</p><p><strong>2. 开始洗车</strong> — 支付成功后,洗车机自动启动,按照设备屏幕提示将车辆驶入指定位置。</p><p><strong>3. 完成取车</strong> — 洗车结束后,设备会有语音和灯光提示,将车辆驶出即可。洗车记录会自动保存在「我的订单」中。</p>"
+    answer: "<p>使用Yeswash自助洗车非常简单,只需三步:</p><p><strong>1. 扫码启动</strong> — 打开小程序,扫描洗车机上的二维码,选择洗车套餐并支付。</p><p><strong>2. 开始洗车</strong> — 支付成功后,按照设备屏幕提示将车辆驶入指定位置,确认无误后在屏幕上点击开始洗车。</p><p><strong>3. 完成取车</strong> — 洗车结束后,设备会有语音和灯光提示,将车辆驶出即可。洗车记录会自动保存在「我的订单」中。</p>"
   },
   },
   {
   {
     question: "洗车前需要做哪些准备?",
     question: "洗车前需要做哪些准备?",
-    answer: "<p>为了确保洗车效果和车辆安全,请注意以下事项:</p><p>• 关闭所有车窗和天窗,确保完全密闭</p><p>• 收起外后视镜(如车辆支持电动折叠)</p><p>• 检查并收好车外天线(如有可拆卸天线请提前取下)</p><p>• 确认油箱盖已盖紧</p><p>• 车身如有明显大块泥沙、污物,建议先简单清理</p><p>• 车辆改装件(尾翼、行李架等)请确认安装牢固</p>"
+    answer: "<p>为了确保洗车效果和车辆安全,请注意以下事项:</p><p>• 关闭所有车窗和天窗,确保完全密闭</p><p>• 检查并收好车外天线(如有可拆卸天线请提前取下)</p><p>• 确认油箱盖已盖紧</p><p>• 车身如有明显大块泥沙、污物,建议先简单清理</p><p>• 车辆改装件(尾翼、行李架等)请确认安装牢固</p>"
   },
   },
   {
   {
     question: "洗车过程中有哪些注意事项?",
     question: "洗车过程中有哪些注意事项?",
     answer: "<p>洗车过程中请务必注意:</p><p>• 车辆挂P挡、拉好手刹,发动机熄火</p><p>• 不要留在车内,在指定安全区域等候</p><p>• 不要在洗车机运行期间靠近或触摸设备</p><p>• 如遇设备异常或异响,请立即按下急停按钮</p><p>• 不要在雷雨天气使用洗车设备</p>"
     answer: "<p>洗车过程中请务必注意:</p><p>• 车辆挂P挡、拉好手刹,发动机熄火</p><p>• 不要留在车内,在指定安全区域等候</p><p>• 不要在洗车机运行期间靠近或触摸设备</p><p>• 如遇设备异常或异响,请立即按下急停按钮</p><p>• 不要在雷雨天气使用洗车设备</p>"
   },
   },
-  {
-    question: "支持哪些支付方式?",
-    answer: "<p>目前Yeswash支持以下支付方式:</p><p>• <strong>账户余额</strong> — 充值后使用余额支付,方便快捷,推荐充值享受更多优惠</p><p>• <strong>微信支付</strong> — 直接调用微信支付完成付款</p><p>充值路径:进入「我的」→「我的钱包」→「充值」,选择金额完成充值即可。</p>"
-  },
   {
   {
     question: "洗车后如何查看订单?",
     question: "洗车后如何查看订单?",
     answer: "<p>洗车完成后,订单会自动保存,您可以通过以下方式查看:</p><p>进入「我的」→「我的订单」,即可查看所有历史洗车记录。点击具体订单可查看详情,包括洗车时间、消费金额、洗车网点等信息。</p>"
     answer: "<p>洗车完成后,订单会自动保存,您可以通过以下方式查看:</p><p>进入「我的」→「我的订单」,即可查看所有历史洗车记录。点击具体订单可查看详情,包括洗车时间、消费金额、洗车网点等信息。</p>"
   },
   },
   {
   {
     question: "遇到问题如何联系客服?",
     question: "遇到问题如何联系客服?",
-    answer: "<p>如在使用过程中遇到任何问题,可通过以下方式联系我们:</p><p>• 进入「我的」→「联系我们」,直接拨打客服电话</p><p>• 如有设备故障或洗车质量问题,可通过「纠错上报」提交反馈,我们会尽快处理</p><p>客服工作时间:每日 7:00 - 22:00</p>"
+    answer: "<p>如在使用过程中遇到任何问题,可通过以下方式联系我们:</p><p>• 进入「首页」→「在线客服」,联系在线客服获取帮助</p><p>• 查看站点详情页的服务电话,直接联系站点工作人员</p><p>• 如有设备故障或洗车质量问题,可通过「故障反馈」提交反馈,我们会尽快处理</p><p>客服工作时间:每日 9:00 - 22:00</p>"
   },
   },
   {
   {
     question: "哪些车型不适合自助洗车?",
     question: "哪些车型不适合自助洗车?",
     answer: "<p>以下类型的车辆可能不适合使用自助洗车机:</p><p>• 车身高度超过2.2米的车辆(如大型SUV、房车等)</p><p>• 车身宽度超过2.1米的车辆</p><p>• 装有非原厂大型改装件的车辆</p><p>• 车身存在严重破损或漆面大面积脱落的车辆</p><p>如不确定您的车辆是否适用,请先联系客服确认。</p>"
     answer: "<p>以下类型的车辆可能不适合使用自助洗车机:</p><p>• 车身高度超过2.2米的车辆(如大型SUV、房车等)</p><p>• 车身宽度超过2.1米的车辆</p><p>• 装有非原厂大型改装件的车辆</p><p>• 车身存在严重破损或漆面大面积脱落的车辆</p><p>如不确定您的车辆是否适用,请先联系客服确认。</p>"
   },
   },
-  {
-    question: "洗车套餐有哪些选择?",
-    answer: "<p>不同网点提供的套餐可能略有差异,常见套餐包括:</p><p>• <strong>标准洗</strong> — 高压冲洗+泡沫洗+清水冲洗+风干,适合日常清洁</p><p>• <strong>精洗</strong> — 在标准洗基础上增加刷洗环节,清洁更彻底</p><p>• <strong>打蜡洗</strong> — 洗车同时进行水蜡护理,让车漆更亮丽</p><p>具体套餐和价格以扫码后显示的为准。</p>"
-  },
 ];
 ];
 
 
 const state = reactive({
 const state = reactive({

+ 1 - 1
car-wash-mp/src/pages-user/feedback/add.vue

@@ -2,7 +2,7 @@
   <view>
   <view>
     <uv-popup ref="popup_ref" mode="bottom" custom-style="min-height: 800rpx;padding:15rpx;overflow-y:scroll;" round="10" closeable safeAreaInsetTop
     <uv-popup ref="popup_ref" mode="bottom" custom-style="min-height: 800rpx;padding:15rpx;overflow-y:scroll;" round="10" closeable safeAreaInsetTop
               @close="close">
               @close="close">
-      <view class="w100 flex-center">纠错上报</view>
+      <view class="w100 flex-center">故障反馈</view>
       <uv-form
       <uv-form
           labelPosition="top"
           labelPosition="top"
           labelWidth="100"
           labelWidth="100"

+ 3 - 68
car-wash-mp/src/pages-user/feedback/index.vue

@@ -1,6 +1,6 @@
 <template>
 <template>
   <view class="page">
   <view class="page">
-    <uv-navbar title="纠错上报" bgColor="#C6171E" leftIconColor="#FFFFFF" :titleStyle="{ color: '#FFFFFF' }" :autoBack="true" :placeholder="true"></uv-navbar>
+    <uv-navbar title="故障反馈" bgColor="#C6171E" leftIconColor="#FFFFFF" :titleStyle="{ color: '#FFFFFF' }" :autoBack="true" :placeholder="true"></uv-navbar>
     <view class="sheet">
     <view class="sheet">
       <uv-list border>
       <uv-list border>
         <uv-list-item
         <uv-list-item
@@ -20,21 +20,6 @@
     </view>
     </view>
 
 
 
 
-    <view
-        class="flex-center flex-column contact mt-20"
-        hover-class="hover-scale"
-        @click="call"
-    >
-
-      <image
-          @click="handleCallPhone"
-          class="width-96"
-          mode="widthFix"
-          src="/static/contact-customer.png"/>
-
-      <view class="mt-16 color-666 fs-28">电话客服</view>
-    </view>
-
     <view class="feedback-plus" @click="handleAddFeedback">
     <view class="feedback-plus" @click="handleAddFeedback">
       <uv-icon name="plus" color="#FFFFFF"></uv-icon>
       <uv-icon name="plus" color="#FFFFFF"></uv-icon>
     </view>
     </view>
@@ -45,75 +30,31 @@
 </template>
 </template>
 
 
 <script setup lang="ts">
 <script setup lang="ts">
-import {onHide, onShow} from "@dcloudio/uni-app";
+import {onShow} from "@dcloudio/uni-app";
 import {reactive, ref} from "vue";
 import {reactive, ref} from "vue";
 import {body} from "@/utils/https"
 import {body} from "@/utils/https"
 
 
 import add from '@/pages-user/feedback/add.vue';
 import add from '@/pages-user/feedback/add.vue';
-import {getServicePhone} from "@/utils/common";
 
 
 const add_ref = ref()
 const add_ref = ref()
 const detail_ref = ref()
 const detail_ref = ref()
 
 
 const initState = () => ({
 const initState = () => ({
-  feedbackList: [
-    // {
-    //   title: '洗车扣费异常问题',
-    //   status: 1,
-    //   createTime: '2022-09-01 10:00:00',
-    // },
-    // {
-    //   title: '洗车扣费异常问题',
-    //   status: 1,
-    //   createTime: '2022-09-01 10:00:00',
-    // }
-  ] as any[],
-  servicerPhone: "",
+  feedbackList: [] as any[],
 })
 })
 
 
 const state = reactive(initState())
 const state = reactive(initState())
 
 
-const call = () => {
-  uni.makePhoneCall({
-    phoneNumber: state.servicerPhone,
-  });
-};
-
-const toggle = (index: number) => {
-  state.feedbackList = state.feedbackList.map((item, i) => {
-    return {
-      ...item,
-      open: item.open ? false : i === index,
-    };
-  });
-};
-
 onShow(() => {
 onShow(() => {
-  let gd = getApp<any>().globalData;
-  state.servicerPhone = getServicePhone();
-  // getApp<any>().globalData.config?.servicePhone;
   loadDataList()
   loadDataList()
 });
 });
 
 
-const handleCallPhone = () => {
-  let servicePhone = getServicePhone();
-  uni.makePhoneCall({
-    phoneNumber: servicePhone,
-    fail: (error) => {
-    }
-  });
-}
-
 const loadDataList = () => {
 const loadDataList = () => {
   body(`/feedback/list`).then((res: any) => {
   body(`/feedback/list`).then((res: any) => {
     state.feedbackList = res.list;
     state.feedbackList = res.list;
   })
   })
 }
 }
 
 
-onHide(() => {
-  Object.assign(state, initState());
-})
-
 const handleClickFaq = (item: any) => {
 const handleClickFaq = (item: any) => {
   detail_ref.value?.open(item, 'detail')
   detail_ref.value?.open(item, 'detail')
 }
 }
@@ -131,12 +72,6 @@ const handleAddFeedback = () => {
   padding: 40rpx 32rpx;
   padding: 40rpx 32rpx;
 }
 }
 
 
-.contact {
-  height: 216rpx;
-  border-radius: 24rpx;
-  background: $uni-bg-color-card;
-}
-
 .sheet {
 .sheet {
   box-sizing: border-box;
   box-sizing: border-box;
   border-radius: 24rpx;
   border-radius: 24rpx;

+ 12 - 0
car-wash-mp/src/pages-wash/device/index.vue

@@ -7,6 +7,7 @@
         <view class="device-number">
         <view class="device-number">
           <uv-icon name="car" size="24" color="#C6171E"></uv-icon>
           <uv-icon name="car" size="24" color="#C6171E"></uv-icon>
           <text class="number-text">洗车机 No.{{ state.device?.shortId }}</text>
           <text class="number-text">洗车机 No.{{ state.device?.shortId }}</text>
+          <view v-if="state.device?.hasPa" class="pa-badge">PA</view>
         </view>
         </view>
 
 
         <view class="device-status" :class="'status-' + (state.device?.state || 'idle')">
         <view class="device-status" :class="'status-' + (state.device?.state || 'idle')">
@@ -357,6 +358,17 @@ const handleGotoRechage = () => {
       font-weight: $uni-font-weight-semibold;
       font-weight: $uni-font-weight-semibold;
       color: $uni-text-color;
       color: $uni-text-color;
     }
     }
+
+    .pa-badge {
+      margin-left: 12rpx;
+      padding: 2rpx 12rpx;
+      background: #C6171E;
+      color: #FFFFFF;
+      border-radius: 6rpx;
+      font-size: 22rpx;
+      font-weight: 700;
+      line-height: 1.4;
+    }
   }
   }
 
 
   .device-status {
   .device-status {

+ 1 - 1
car-wash-mp/src/pages.json

@@ -68,7 +68,7 @@
           "path": "feedback/index",
           "path": "feedback/index",
           "style": {
           "style": {
             "navigationStyle": "custom",
             "navigationStyle": "custom",
-            "navigationBarTitleText": "纠错上报"
+            "navigationBarTitleText": "故障反馈"
           }
           }
         },
         },
         {
         {

+ 12 - 4
car-wash-mp/src/pages/index/index.vue

@@ -165,7 +165,7 @@
             <text class="notice-card-title">{{ item.title }}</text>
             <text class="notice-card-title">{{ item.title }}</text>
             <view class="notice-card-divider"></view>
             <view class="notice-card-divider"></view>
             <text class="notice-card-content">{{ item.content }}</text>
             <text class="notice-card-content">{{ item.content }}</text>
-            <text class="notice-card-time" v-if="item.startTime">{{ item.startTime }} — {{ item.endTime }}</text>
+            <text class="notice-card-time" v-if="item.createTime">发布于 {{ formatDate(item.createTime) }}</text>
           </view>
           </view>
         </scroll-view>
         </scroll-view>
         <view class="notice-popup-foot">
         <view class="notice-popup-foot">
@@ -334,6 +334,11 @@ const loadNoticeList = () => {
   })
   })
 }
 }
 
 
+const formatDate = (datetime: string) => {
+  if (!datetime) return '';
+  return datetime.split(' ')[0];
+}
+
 const handleNoticeClick = () => {
 const handleNoticeClick = () => {
   noticePopupVisible.value = true;
   noticePopupVisible.value = true;
 }
 }
@@ -804,7 +809,7 @@ page {
 }
 }
 
 
 .notice-popup {
 .notice-popup {
-  width: 630rpx;
+  width: 660rpx;
   max-height: 78vh;
   max-height: 78vh;
   background: #fff;
   background: #fff;
   border-radius: 24rpx;
   border-radius: 24rpx;
@@ -865,11 +870,11 @@ page {
 .notice-popup-body {
 .notice-popup-body {
   flex: 1;
   flex: 1;
   overflow-y: auto;
   overflow-y: auto;
-  padding: 0 28rpx;
+  padding: 0 32rpx;
 }
 }
 
 
 .notice-card {
 .notice-card {
-  padding: 28rpx 28rpx 24rpx;
+  padding: 32rpx 32rpx 28rpx;
   margin-bottom: 20rpx;
   margin-bottom: 20rpx;
   border-radius: 16rpx;
   border-radius: 16rpx;
   background: #fff;
   background: #fff;
@@ -883,6 +888,7 @@ page {
   color: #1a1a1a;
   color: #1a1a1a;
   line-height: 1.5;
   line-height: 1.5;
   display: block;
   display: block;
+  padding-right: 8rpx;
 }
 }
 
 
 .notice-card-divider {
 .notice-card-divider {
@@ -900,6 +906,7 @@ page {
   line-height: 1.9;
   line-height: 1.9;
   display: block;
   display: block;
   letter-spacing: 0.5rpx;
   letter-spacing: 0.5rpx;
+  padding-right: 8rpx;
 }
 }
 
 
 .notice-card-time {
 .notice-card-time {
@@ -908,6 +915,7 @@ page {
   font-size: 22rpx;
   font-size: 22rpx;
   color: #bbb;
   color: #bbb;
   letter-spacing: 0.3rpx;
   letter-spacing: 0.3rpx;
+  padding-right: 8rpx;
 }
 }
 
 
 .notice-popup-foot {
 .notice-popup-foot {

+ 1 - 1
car-wash-mp/src/pages/user/index.vue

@@ -142,7 +142,7 @@ const menu = ref([
     icon: '/static/iconfont/default/guide.svg'
     icon: '/static/iconfont/default/guide.svg'
   },
   },
   {
   {
-    title: "纠错上报",
+    title: "故障反馈",
     path: "/pages-user/feedback/index",
     path: "/pages-user/feedback/index",
     icon: '/static/user/feedback.png'
     icon: '/static/user/feedback.png'
   },
   },

+ 1 - 0
car-wash-service/src/main/java/com/kym/service/awoara/event/handle/DeviceStateEventHandler.java

@@ -43,6 +43,7 @@ public class DeviceStateEventHandler implements AwoaraEventHandler<DeviceStateOb
                 .set(WashDevice::getFsmState, deviceState.getFsm_state())
                 .set(WashDevice::getFsmState, deviceState.getFsm_state())
                 .set(WashDevice::getHasWater, deviceState.getHas_water())
                 .set(WashDevice::getHasWater, deviceState.getHas_water())
                 .set(WashDevice::getHasFoam, deviceState.getHas_foam())
                 .set(WashDevice::getHasFoam, deviceState.getHas_foam())
+                .set(WashDevice::getHasPa, deviceState.getHas_pa())
                 .set(WashDevice::getTemperatureChip, deviceState.getTemperature_chip())
                 .set(WashDevice::getTemperatureChip, deviceState.getTemperature_chip())
                 .eq(WashDevice::getProductKey, productKey)
                 .eq(WashDevice::getProductKey, productKey)
                 .eq(WashDevice::getDeviceName, deviceName)
                 .eq(WashDevice::getDeviceName, deviceName)