CityList.vue 11.6 KB
<template>
  <div>
    <a-card title="租户管理" :bordered="false" class="list-table-card">
      <div class="list-toolbar">
        <div class="list-toolbar-right">
          <a-button type="primary" @click="openAdd">新增</a-button>
        </div>
      </div>
      <a-table :dataSource="list" :columns="columns" :loading="loading" rowKey="id" :pagination="false">
        <template #bodyCell="{ column, record }">
          <template v-if="column.key === 'status'">
            <a-tag :color="record.status === 1 ? 'green' : 'default'">
              {{ record.status === 1 ? '已开通' : '未开通' }}
            </a-tag>
          </template>
          <template v-if="column.key === 'action'">
            <a-space>
              <a @click="openEdit(record)">编辑</a>
              <a @click="openConfig(record)">配送费配置</a>
              <a @click="openLevelConfig(record)">骑手等级</a>
              <a-popconfirm :title="record.status === 1 ? '确认关闭?' : '确认开通?'" @confirm="toggleStatus(record)">
                <a>{{ record.status === 1 ? '关闭' : '开通' }}</a>
              </a-popconfirm>
            </a-space>
          </template>
        </template>
      </a-table>
    </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 v-model:value="form.name" placeholder="如:华东一区 / 某租户名" />
        </a-form-item>
        <a-form-item label="区划码/编号(选填)">
          <a-input v-model:value="form.areaCode" placeholder="行政区划码或自定义编号" />
        </a-form-item>
        <a-form-item label="平台抽成比例(%)">
          <a-input-number v-model:value="form.rate" :min="0" :max="100" style="width:100%" />
        </a-form-item>
        <a-form-item label="排序">
          <a-input-number v-model:value="form.listOrder" :min="0" style="width:100%" />
        </a-form-item>
      </a-form>
    </a-modal>


    <a-modal v-model:open="levelVisible" :title="`骑手等级配置 - ${levelCityName}`" width="900px" :footer="null">
      <div style="margin-bottom:16px;text-align:right">
        <a-button type="primary" @click="openLevelAdd">新增等级</a-button>
      </div>
      <a-table :dataSource="levelList" :columns="levelColumns" :loading="levelLoading" 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-if="column.key === 'runFeeMode'">
            {{ runFeeModeMap[record.runFeeMode] || '-' }}
          </template>
          <template v-if="column.key === 'rule'">
            {{ formatLevelRule(record) }}
          </template>
          <template v-if="column.key === 'action'">
            <a-space>
              <a @click="openLevelEdit(record)">编辑</a>
              <a v-if="record.isDefault !== 1" @click="handleSetDefault(record)">设为默认</a>
              <a-popconfirm title="确认删除该等级?" @confirm="handleDeleteLevel(record)">
                <a style="color:red">删除</a>
              </a-popconfirm>
            </a-space>
          </template>
        </template>
      </a-table>
    </a-modal>

    <a-modal v-model:open="levelEditVisible" :title="levelEditingId ? '编辑骑手等级' : '新增骑手等级'" @ok="handleSaveLevel" :confirmLoading="levelSaving">
      <a-form :model="levelForm" layout="vertical">
        <a-form-item label="等级编号">
          <a-input-number v-model:value="levelForm.levelId" :min="1" style="width:100%" />
        </a-form-item>
        <a-form-item label="等级名称">
          <a-input v-model:value="levelForm.name" placeholder="如:标准骑手 / 金牌骑手" />
        </a-form-item>
        <a-form-item label="每日转单上限">
          <a-input-number v-model:value="levelForm.transNums" :min="0" style="width:100%" />
        </a-form-item>
        <a-form-item label="收入模式">
          <a-radio-group v-model:value="levelForm.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="levelForm.runFeeMode === 1">
          <a-form-item label="固定收入(元)">
            <a-input-number v-model:value="levelForm.runFixMoney" :min="0" :step="0.1" style="width:100%" />
          </a-form-item>
        </template>
        <template v-else-if="levelForm.runFeeMode === 2">
          <a-form-item label="收入比例(%)">
            <a-input-number v-model:value="levelForm.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="levelForm.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="levelForm.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="levelForm.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="levelForm.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 { useRouter } from 'vue-router'
import { message } from 'ant-design-vue'
import { cityApi, riderLevelApi } from '@/api'

const router = useRouter()
const loading = ref(false)
const saving = ref(false)
const list = ref<any[]>([])
const modalVisible = ref(false)
const levelVisible = ref(false)
const levelEditVisible = ref(false)
const editingId = ref<number | null>(null)
const levelCityId = ref<number>(0)
const levelCityName = ref('')
const form = reactive({ name: '', areaCode: '', rate: 0, listOrder: 0 })

const levelLoading = ref(false)
const levelSaving = ref(false)
const levelList = ref<any[]>([])
const levelEditingId = ref<number | null>(null)
const levelForm = 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: 'ID', dataIndex: 'id', key: 'id', width: 80 },
  { title: '名称', dataIndex: 'name', key: 'name' },
  { title: '区划码/编号', dataIndex: 'areaCode', key: 'areaCode' },
  { title: '抽成%', dataIndex: 'rate', key: 'rate' },
  { title: '状态', key: 'status' },
  { title: '操作', key: 'action' },
]

const levelColumns = [
  { 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 loadList() {
  loading.value = true
  try {
    const res: any = await cityApi.tree()
    list.value = res.data
  } finally {
    loading.value = false
  }
}

function openAdd() {
  editingId.value = null
  Object.assign(form, { name: '', areaCode: '', rate: 0, listOrder: 0 })
  modalVisible.value = true
}

function openEdit(record: any) {
  editingId.value = record.id
  Object.assign(form, { name: record.name, areaCode: record.areaCode, rate: record.rate, listOrder: record.listOrder })
  modalVisible.value = true
}

async function handleSave() {
  saving.value = true
  try {
    if (editingId.value) {
      await cityApi.edit({ ...form, id: editingId.value })
    } else {
      await cityApi.add(form)
    }
    message.success('保存成功')
    modalVisible.value = false
    loadList()
  } finally {
    saving.value = false
  }
}

async function toggleStatus(record: any) {
  await cityApi.setStatus(record.id, record.status === 1 ? 0 : 1)
  message.success('操作成功')
  loadList()
}

function openConfig(record: any) {
  router.push({ path: '/config/fee-plan', query: { cityId: String(record.id) } })
}

function openLevelConfig(record: any) {
  levelCityId.value = record.id
  levelCityName.value = record.name
  levelVisible.value = true
  loadLevels()
}

async function loadLevels() {
  levelLoading.value = true
  try {
    const res: any = await riderLevelApi.list(levelCityId.value)
    levelList.value = Array.isArray(res?.data) ? res.data : []
  } finally {
    levelLoading.value = false
  }
}

function openLevelAdd() {
  levelEditingId.value = null
  Object.assign(levelForm, {
    cityId: levelCityId.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,
  })
  levelEditVisible.value = true
}

function openLevelEdit(record: any) {
  levelEditingId.value = record.id
  Object.assign(levelForm, {
    cityId: levelCityId.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,
  })
  levelEditVisible.value = true
}

async function handleSaveLevel() {
  if (!levelForm.name) {
    message.error('请填写等级名称')
    return
  }
  levelSaving.value = true
  try {
    const payload = { ...levelForm, id: levelEditingId.value || undefined }
    if (levelEditingId.value) {
      await riderLevelApi.edit(payload)
    } else {
      await riderLevelApi.add(payload)
    }
    message.success('保存成功')
    levelEditVisible.value = false
    loadLevels()
  } finally {
    levelSaving.value = false
  }
}

async function handleSetDefault(record: any) {
  await riderLevelApi.setDefault(record.id, levelCityId.value)
  message.success('设置成功')
  loadLevels()
}

async function handleDeleteLevel(record: any) {
  await riderLevelApi.del(record.id, levelCityId.value)
  message.success('删除成功')
  loadLevels()
}

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(loadList)
</script>