RiderLevelList.vue 9.51 KB
<template>
  <div>
    <a-card title="骑手等级" :bordered="false" class="list-table-card">
      <div class="list-toolbar">
        <div class="list-toolbar-left">
          <a-select
            v-if="isAdmin"
            v-model:value="selectedCityId"
            placeholder="选择租户"
            class="list-filter"
            @change="loadList"
          >
            <a-select-option v-for="c in cityList" :key="c.id" :value="c.id">{{ c.name }}</a-select-option>
          </a-select>
          <div v-else class="managed-city-pill">当前租户:{{ currentCityName || `租户#${selectedCityId}` }}</div>
        </div>
        <div class="list-toolbar-right">
          <a-button type="primary" :disabled="!selectedCityId" @click="openAdd">新增等级</a-button>
        </div>
      </div>

      <template v-if="selectedCityId">
        <div class="soft-note-card page-note-card">
          <strong>骑手等级说明</strong>
          <p>等级用于控制骑手收入规则和转单上限。平台管理员需先选择租户,分站管理员默认管理当前租户。</p>
        </div>

        <a-table :dataSource="levelList" :columns="columns" :loading="loading" rowKey="id" :pagination="false">
          <template #bodyCell="{ column, record }">
            <template v-if="column.key === 'isDefault'">
              <a-tag :color="record.isDefault === 1 ? 'green' : 'default'">
                {{ record.isDefault === 1 ? '默认' : '普通' }}
              </a-tag>
            </template>
            <template v-else-if="column.key === 'runFeeMode'">
              {{ runFeeModeMap[record.runFeeMode] || '-' }}
            </template>
            <template v-else-if="column.key === 'rule'">
              {{ formatLevelRule(record) }}
            </template>
            <template v-else-if="column.key === 'action'">
              <a-space>
                <a @click="openEdit(record)">编辑</a>
                <a v-if="record.isDefault !== 1" @click="handleSetDefault(record)">设为默认</a>
                <a-popconfirm title="确认删除该等级?" @confirm="handleDelete(record)">
                  <a style="color:red">删除</a>
                </a-popconfirm>
              </a-space>
            </template>
          </template>
        </a-table>
      </template>

      <a-empty v-else description="请先选择租户" />
    </a-card>

    <a-modal
      v-model:open="modalVisible"
      :title="editingId ? '编辑骑手等级' : '新增骑手等级'"
      @ok="handleSave"
      :confirmLoading="saving"
    >
      <a-form :model="form" layout="vertical">
        <a-form-item label="等级编号">
          <a-input-number v-model:value="form.levelId" :min="1" style="width:100%" />
        </a-form-item>
        <a-form-item label="等级名称">
          <a-input v-model:value="form.name" placeholder="如:标准骑手 / 金牌骑手" />
        </a-form-item>
        <a-form-item label="每日转单上限">
          <a-input-number v-model:value="form.transNums" :min="0" style="width:100%" />
        </a-form-item>
        <a-form-item label="收入模式">
          <a-radio-group v-model:value="form.runFeeMode">
            <a-radio :value="1">固定金额</a-radio>
            <a-radio :value="2">按比例</a-radio>
            <a-radio :value="3">按距离</a-radio>
          </a-radio-group>
        </a-form-item>
        <template v-if="form.runFeeMode === 1">
          <a-form-item label="固定收入(元)">
            <a-input-number v-model:value="form.runFixMoney" :min="0" :step="0.1" style="width:100%" />
          </a-form-item>
        </template>
        <template v-else-if="form.runFeeMode === 2">
          <a-form-item label="收入比例(%)">
            <a-input-number v-model:value="form.runRate" :min="0" :max="100" :step="0.1" style="width:100%" />
          </a-form-item>
        </template>
        <template v-else>
          <a-row :gutter="16">
            <a-col :span="12">
              <a-form-item label="起始距离(米)">
                <a-input-number v-model:value="form.distanceBasic" :min="0" style="width:100%" />
              </a-form-item>
            </a-col>
            <a-col :span="12">
              <a-form-item label="基础收入(元)">
                <a-input-number v-model:value="form.distanceBasicMoney" :min="0" :step="0.1" style="width:100%" />
              </a-form-item>
            </a-col>
          </a-row>
          <a-row :gutter="16">
            <a-col :span="12">
              <a-form-item label="超出每公里收入(元)">
                <a-input-number v-model:value="form.distanceMoreMoney" :min="0" :step="0.1" style="width:100%" />
              </a-form-item>
            </a-col>
            <a-col :span="12">
              <a-form-item label="最高收入上限(元)">
                <a-input-number v-model:value="form.distanceMaxMoney" :min="0" :step="0.1" style="width:100%" />
              </a-form-item>
            </a-col>
          </a-row>
        </template>
      </a-form>
    </a-modal>
  </div>
</template>

<script setup lang="ts">
import { onMounted, reactive, ref } from 'vue'
import { useRoute } from 'vue-router'
import { message } from 'ant-design-vue'
import { riderLevelApi } from '@/api'
import { useRoleSelectedCity } from '@/composables/useRoleSelectedCity'

const route = useRoute()
const { isAdmin, cityList, selectedCityId, currentCityName, loadCities } = useRoleSelectedCity()

const loading = ref(false)
const saving = ref(false)
const modalVisible = ref(false)
const editingId = ref<number | null>(null)
const levelList = ref<any[]>([])
const form = reactive({
  cityId: 0,
  levelId: 1,
  name: '',
  transNums: 0,
  runFeeMode: 1,
  runFixMoney: 0,
  runRate: 0,
  distanceBasic: 0,
  distanceBasicMoney: 0,
  distanceMoreMoney: 0,
  distanceMaxMoney: 0,
})

const columns = [
  { title: '等级编号', dataIndex: 'levelId', width: 100 },
  { title: '等级名称', dataIndex: 'name' },
  { title: '默认', key: 'isDefault', width: 90 },
  { title: '转单上限', dataIndex: 'transNums', width: 100 },
  { title: '收入模式', key: 'runFeeMode', width: 110 },
  { title: '规则', key: 'rule' },
  { title: '操作', key: 'action', width: 220 },
]

const runFeeModeMap: Record<number, string> = {
  1: '固定金额',
  2: '按比例',
  3: '按距离',
}

async function initPage() {
  const queryCityId = Number(route.query.cityId || 0) || undefined
  await loadCities(queryCityId)
  if (selectedCityId.value) {
    await loadList()
  }
}

async function loadList() {
  if (!selectedCityId.value) {
    levelList.value = []
    return
  }
  loading.value = true
  try {
    const res: any = await riderLevelApi.list(selectedCityId.value)
    levelList.value = Array.isArray(res?.data) ? res.data : []
  } finally {
    loading.value = false
  }
}

function openAdd() {
  if (!selectedCityId.value) {
    message.error('请先选择租户')
    return
  }
  editingId.value = null
  Object.assign(form, {
    cityId: selectedCityId.value,
    levelId: (levelList.value[levelList.value.length - 1]?.levelId || 0) + 1,
    name: '',
    transNums: 0,
    runFeeMode: 1,
    runFixMoney: 0,
    runRate: 0,
    distanceBasic: 0,
    distanceBasicMoney: 0,
    distanceMoreMoney: 0,
    distanceMaxMoney: 0,
  })
  modalVisible.value = true
}

function openEdit(record: any) {
  if (!selectedCityId.value) {
    return
  }
  editingId.value = record.id
  Object.assign(form, {
    cityId: selectedCityId.value,
    levelId: record.levelId,
    name: record.name,
    transNums: record.transNums,
    runFeeMode: record.runFeeMode,
    runFixMoney: record.runFixMoney ?? 0,
    runRate: record.runRate ?? 0,
    distanceBasic: record.distanceBasic ?? 0,
    distanceBasicMoney: record.distanceBasicMoney ?? 0,
    distanceMoreMoney: record.distanceMoreMoney ?? 0,
    distanceMaxMoney: record.distanceMaxMoney ?? 0,
  })
  modalVisible.value = true
}

async function handleSave() {
  if (!selectedCityId.value) {
    message.error('请先选择租户')
    return
  }
  if (!form.name.trim()) {
    message.error('请填写等级名称')
    return
  }
  saving.value = true
  try {
    const payload = { ...form, cityId: selectedCityId.value, id: editingId.value || undefined }
    if (editingId.value) {
      await riderLevelApi.edit(payload)
    } else {
      await riderLevelApi.add(payload)
    }
    message.success('保存成功')
    modalVisible.value = false
    await loadList()
  } finally {
    saving.value = false
  }
}

async function handleSetDefault(record: any) {
  if (!selectedCityId.value) {
    return
  }
  await riderLevelApi.setDefault(record.id, selectedCityId.value)
  message.success('设置成功')
  await loadList()
}

async function handleDelete(record: any) {
  if (!selectedCityId.value) {
    return
  }
  await riderLevelApi.del(record.id, selectedCityId.value)
  message.success('删除成功')
  await loadList()
}

function formatLevelRule(record: any) {
  if (record.runFeeMode === 1) {
    return `固定 ${record.runFixMoney ?? 0} 元`
  }
  if (record.runFeeMode === 2) {
    return `按配送费 ${record.runRate ?? 0}%`
  }
  return `起始${record.distanceBasic ?? 0}米/${record.distanceBasicMoney ?? 0}元,超出每公里${record.distanceMoreMoney ?? 0}元,上限${record.distanceMaxMoney ?? 0}元`
}

onMounted(initPage)
</script>

<style scoped>
.managed-city-pill {
  display: inline-flex;
  align-items: center;
  min-height: 36px;
  padding: 0 14px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--panel-strong);
  color: var(--text-soft);
  font-size: 12px;
}

.page-note-card {
  margin-bottom: 16px;
}
</style>