Browse Source

feat(duty): sync public H5 with time, work plans, and remark

Co-authored-by: Cursor <cursoragent@cursor.com>
zlwu 2 months ago
parent
commit
8d9f0b259e
1 changed files with 52 additions and 12 deletions
  1. 52 12
      web-admin/src/views/public/duty/index.vue

+ 52 - 12
web-admin/src/views/public/duty/index.vue

@@ -6,12 +6,17 @@
       <h2>链接无效或已失效</h2>
       <p>请确认是否复制完整,或向管理员重新索取当日值班链接。</p>
     </div>
-    <div v-else-if="errorType === 'closed' || page?.linkStatus === 'closed' || page?.closed" class="state">
+    <div
+      v-else-if="errorType === 'closed' || page?.linkStatus === 'closed' || page?.closed"
+      class="state"
+    >
       <div class="icon off">⊘</div>
       <h2>报名已关闭</h2>
       <p>管理员已关闭本链接,暂时无法继续抢班。</p>
       <div v-if="page?.dutyDate" class="card">
-        <div class="kv"><span>日期</span><span>{{ page.dutyDate }}</span></div>
+        <div class="kv"
+          ><span>日期</span><span>{{ page.dutyDate }}</span></div
+        >
       </div>
     </div>
     <div v-else-if="success" class="page">
@@ -25,9 +30,15 @@
         <h2>已抢到{{ success.shiftLabel }}</h2>
         <p>{{ success.dutyDate }}</p>
         <div class="card">
-          <div class="kv"><span>日期</span><span>{{ success.dutyDate }}</span></div>
-          <div class="kv"><span>班次</span><span>{{ success.shiftLabel }}</span></div>
-          <div class="kv"><span>姓名</span><span>{{ success.personName }}</span></div>
+          <div class="kv"
+            ><span>日期</span><span>{{ success.dutyDate }}</span></div
+          >
+          <div class="kv"
+            ><span>班次</span><span>{{ success.shiftLabel }}</span></div
+          >
+          <div class="kv"
+            ><span>姓名</span><span>{{ success.personName }}</span></div
+          >
         </div>
         <button type="button" class="btn secondary" @click="backToList">返回查看当日班次</button>
       </div>
@@ -48,7 +59,7 @@
         <section v-for="slot in page.slots" :key="slot.shiftType" class="slot">
           <div class="slot-hd">
             <div class="title">
-              <i class="dot" :class="slot.shiftType"></i>
+              <i class="dot" :class="dotClass(slot.shiftType)"></i>
               {{ slot.shiftLabel || slot.shiftType }}
             </div>
             <span class="badge" :class="isFull(slot) ? 'full' : 'open'">
@@ -59,12 +70,20 @@
             <span>名额</span>
             <strong>{{ slot.taken }} / {{ slot.capacity }}</strong>
           </div>
-          <p v-if="slot.remark" class="slot-remark">
-            工作安排:<strong>{{ slot.remark }}</strong>
+          <p v-if="slot.timeLabel" class="slot-time">
+            值班时间:<strong>{{ slot.timeLabel }}</strong>
           </p>
-          <div class="bar"><i :style="{ width: barWidth(slot) }" :class="slot.shiftType"></i></div>
+          <p v-if="slot.workPlanLabels?.length" class="slot-remark">
+            工作安排:<strong>{{ slot.workPlanLabels.join('、') }}</strong>
+          </p>
+          <p v-if="slot.remark" class="slot-note">备注:{{ slot.remark }}</p>
+          <div class="bar">
+            <i :style="{ width: barWidth(slot) }" :class="dotClass(slot.shiftType)"></i>
+          </div>
           <div class="people">
-            <span v-for="(a, i) in slot.assignments" :key="i" class="person">{{ a.personName }}</span>
+            <span v-for="(a, i) in slot.assignments" :key="i" class="person">{{
+              a.personName
+            }}</span>
             <span v-if="!slot.assignments?.length" class="person empty">暂无人报名</span>
             <span v-else-if="slot.capacity - slot.taken > 0" class="person empty">
               空缺 {{ slot.capacity - slot.taken }}
@@ -102,7 +121,9 @@
           <button v-else type="button" class="btn" disabled>名额已满</button>
         </section>
       </div>
-      <footer class="note">提交即表示确认当日可到岗值班<br />链接由管理员分享 · 请勿转发无关人员</footer>
+      <footer class="note"
+        >提交即表示确认当日可到岗值班<br />链接由管理员分享 · 请勿转发无关人员</footer
+      >
     </div>
   </div>
 </template>
@@ -142,6 +163,13 @@
     return (slot.taken || 0) >= (slot.capacity || 0)
   }
 
+  function dotClass(shiftType: string) {
+    if (shiftType === 'morning' || shiftType === 'evening' || shiftType === 'duty') {
+      return shiftType
+    }
+    return 'other'
+  }
+
   function barWidth(slot: PublicDutySlot) {
     if (!slot.capacity) return '0%'
     return `${Math.min(100, Math.round((slot.taken / slot.capacity) * 100))}%`
@@ -353,6 +381,9 @@
   .dot.duty {
     background: #d14343;
   }
+  .dot.other {
+    background: #6b7b74;
+  }
   .badge {
     padding: 3px 8px;
     font-size: 11px;
@@ -379,7 +410,9 @@
     font-size: 15px;
     color: #1f2a26;
   }
-  .slot-remark {
+  .slot-time,
+  .slot-remark,
+  .slot-note {
     margin: 8px 0 0;
     font-size: 13px;
     line-height: 1.45;
@@ -387,10 +420,14 @@
     white-space: pre-wrap;
     word-break: break-word;
   }
+  .slot-time strong,
   .slot-remark strong {
     font-weight: 600;
     color: #1f2a26;
   }
+  .slot-note {
+    color: #8a9a93;
+  }
   .bar {
     height: 7px;
     margin-top: 8px;
@@ -413,6 +450,9 @@
   .bar > i.duty {
     background: #d14343;
   }
+  .bar > i.other {
+    background: #6b7b74;
+  }
   .people {
     display: flex;
     flex-wrap: wrap;