yxh
yxh
6 天以前 09dc74e264b6262cbe41c9c8476e24705871d4a6
src/views/ecg/checktype/QueueSequenceForm.vue
@@ -13,15 +13,18 @@
      <template #title>
        <div class="text-13px leading-6">
          正在维护检查项目:<b>{{ checkTypeName }}</b>
          <span class="text-gray-500">(检查项目值 {{ checkTypeValue }},共 {{ list.length }} 个时段)</span>
          <span class="text-gray-500">(检查项目值 {{ checkTypeValue }},共 {{ slotList.length }} 个时段)</span>
        </div>
      </template>
      <div class="text-12px leading-5">
        · <b>起始序号</b>:每天自动重置时回到该值;<b>上限</b>:到达后该时段视为「已满」,患者签到会顺延到后续时段。<br />
        · <b>当前序号</b>:已发到几号,一般无需手工改(每日重置会自动回到"起始序号")。<br />
        · <b>预定额度</b> = 上限 − 起始序号(只读)。<b>上限 = 起始序号 表示该时段没有名额</b>(允许保存,预定额度显示 0 并标红)。<br />
        · 上限 <b>不能小于</b>起始序号,否则该时段永远无法取号。<br />
        · 同一检查项目下<b>同一时段只能有一条规则</b>,重复添加会被拒绝。
        · <b>号段规则</b>:每个时段按顺序占用一段连续号 —— 正常预约号在前,预留号紧跟其后(号更大),
        下一段从上一段的最大号继续,因此<b>号随时段递增、段内连续</b>。<br />
        · <b>起始序号</b>:由系统自动计算(上一段的最大号),<b>不可手工修改</b>。<br />
        · <b>上限</b>:该号池「号满的最大序号」;<b>当前序号</b>:已发到几号(每日重置回起始序号)。<br />
        · <b>取号顺序</b>:普通患者 → 本时段正常预约号;满了 → 本时段<b>预留号</b>(给临时加号);
        再满 → <b>总预留池</b>(无预约时段的患者也直接走总预留池)。<b>总预留池不设上限,保证一定能签到。</b><br />
        · <b>预定额度</b> = 上限 − 起始序号(只读)。上限 = 起始序号 表示该号池无名额(允许保存,显示 0 并标红)。<br />
        · 上限 <b>不能小于</b>起始序号;同一检查项目下<b>同一时段只能有一条规则</b>。
      </div>
    </el-alert>
@@ -39,7 +42,7 @@
    <el-table
      v-loading="loading"
      :data="list"
      :data="slotList"
      :stripe="true"
      border
      class="qs-table"
@@ -58,14 +61,10 @@
      <el-table-column label="正常预约" align="center">
        <el-table-column label="起始序号" align="center" width="90">
          <template #default="scope">
            <el-input-number
              v-model="scope.row.queueSet"
              :min="0"
              :controls="false"
              size="small"
              style="width: 100%"
              @change="markChanged(scope.row)"
            />
            <!-- 【本需求】起始序号 = 号段起点,由系统按顺序自动计算,不允许手工改 -->
            <span class="qs-fixed" :title="'系统自动计算(上一段的最大号)'">
              {{ scope.row.queueSet ?? 0 }}
            </span>
          </template>
        </el-table-column>
        <el-table-column label="上限" align="center" width="80">
@@ -115,14 +114,10 @@
      <el-table-column label="预留" align="center">
        <el-table-column label="起始序号" align="center" width="90">
          <template #default="scope">
            <el-input-number
              v-model="scope.row.queueVipSet"
              :min="0"
              :controls="false"
              size="small"
              style="width: 100%"
              @change="markChanged(scope.row)"
            />
            <!-- 【本需求】预留号段起点,同样由系统自动计算 -->
            <span class="qs-fixed" :title="'系统自动计算(正常预约的上限)'">
              {{ scope.row.queueVipSet ?? 0 }}
            </span>
          </template>
        </el-table-column>
        <el-table-column label="上限" align="center" width="80">
@@ -190,6 +185,28 @@
      </el-table-column>
    </el-table>
    <!--
      【本需求】总预留池(time_slot = 0)
      · 本段普通号 + 本段预留号都发完,或患者没有预约时段时,从总预留池取号;
      · 号段放在当天所有时段之后(号最大 ⇒ 排全天最后),且**不设上限**(永远不会满)。
    -->
    <el-alert type="warning" :closable="false" class="mt-10px">
      <template #title>
        <div class="text-13px">
          总预留池(无时段 / 所有号源用尽时的兜底):
          <template v-if="totalPool">
            起始 <b>{{ totalPool.queueVipSet ?? 0 }}</b> ·
            已发 <b>{{ totalPool.queueVipNo ?? 0 }}</b> ·
            上限 <b>{{ totalPool.queueVipFull ?? 0 }}</b>
            <span class="text-gray-500">(不设上限,满后自动继续发号,保证一定能签到)</span>
          </template>
          <template v-else>
            <span class="text-gray-500">尚未初始化(首次签到时系统会自动创建,号段接在当天最后一段之后)</span>
          </template>
        </div>
      </template>
    </el-alert>
    <!-- 新增 / 编辑表单 -->
    <Dialog v-model="formVisible" :title="formTitle" width="520px" append-to-body>
      <el-form
@@ -219,27 +236,35 @@
            选项来自字典 <code>ecg_book_timeslot</code>;也支持直接输入起始/结束时间后回车新建。
          </div>
        </el-form-item>
        <el-form-item label="普通-起始序号" prop="queueSet">
          <el-input-number v-model="formData.queueSet" :min="0" class="w-full" />
        <el-form-item label="正常预约-起始序号" prop="queueSet">
          <!-- 【本需求】起始序号 = 号段起点,由系统按「检查类型 → 时段顺序」自动计算,不可手工改 -->
          <el-input-number v-model="formData.queueSet" :min="0" class="w-full" disabled />
          <div class="text-12px text-gray-500 leading-5 mt-1">
            系统自动计算(= 上一段的最大号),不需要填写。
          </div>
        </el-form-item>
        <el-form-item label="普通-上限" prop="queueFull">
        <el-form-item label="正常预约-上限" prop="queueFull">
          <!-- 【本次需求】上限允许等于起始序号(=该时段无名额),故 min 改为 0 -->
          <el-input-number v-model="formData.queueFull" :min="0" class="w-full" />
        </el-form-item>
        <el-form-item label="VIP-起始序号" prop="queueVipSet">
          <el-input-number v-model="formData.queueVipSet" :min="0" class="w-full" />
        <el-form-item label="预留-起始序号" prop="queueVipSet">
          <!-- 【本需求】预留号段紧跟正常预约号段之后,由系统自动计算 -->
          <el-input-number v-model="formData.queueVipSet" :min="0" class="w-full" disabled />
          <div class="text-12px text-gray-500 leading-5 mt-1">
            系统自动计算(= 正常预约的上限),不需要填写。
          </div>
        </el-form-item>
        <el-form-item label="VIP-上限" prop="queueVipFull">
        <el-form-item label="预留-上限" prop="queueVipFull">
          <!-- 【本次需求】同普通上限:允许等于起始序号 -->
          <el-input-number v-model="formData.queueVipFull" :min="0" class="w-full" />
        </el-form-item>
        <el-form-item label="普通-当前序号">
        <el-form-item label="正常预约-当前序号">
          <el-input-number v-model="formData.queueNo" :min="0" class="w-full" />
          <div class="text-12px text-gray-500 leading-5 mt-1">
            新增时段时建议与「普通-起始序号」一致。
            新增时段时建议与「正常预约-起始序号」一致。
          </div>
        </el-form-item>
        <el-form-item label="VIP-当前序号">
        <el-form-item label="预留-当前序号">
          <el-input-number v-model="formData.queueVipNo" :min="0" class="w-full" />
        </el-form-item>
      </el-form>
@@ -276,6 +301,19 @@
  () => `预约时段维护${checkTypeName.value ? ' - ' + checkTypeName.value : ''}`
)
const changedCount = computed(() => changedRows.value.size)
/**
 * 【本需求】表格只显示"真实时段"(time_slot <> 0);
 * time_slot = 0 的那一行是「总预留池」(无时段 / 全满时的兜底号池),单独在表格下方展示。
 */
const slotList = computed(() =>
  (list.value || []).filter((r: QueueSequenceVO) => Number(r.timeSlot ?? 0) !== 0)
)
/** 总预留池行(time_slot = 0);未初始化时为 undefined */
const totalPool = computed(() =>
  (list.value || []).find((r: QueueSequenceVO) => Number(r.timeSlot ?? 0) === 0)
)
/** 时段下拉选项:取自字典 ecg_book_timeslot(value 为 HHMMHHMM 数字字符串,label 形如 08:00-08:30) */
const timeSlotOptions = computed(() => {
@@ -503,6 +541,16 @@
}
/* 预定额度(只读):值为 0 时浅红底,表示该时段没有名额 */
/* 【本需求】号段起点(系统自动计算,只读展示) */
.qs-fixed {
  display: inline-block;
  min-width: 34px;
  padding: 1px 4px;
  border-radius: 3px;
  color: var(--el-text-color-secondary);
  background-color: var(--el-fill-color-light);
  font-variant-numeric: tabular-nums;
}
.qs-quota {
  display: inline-block;
  padding: 1px 6px;