141 lines
7.5 KiB
Vue
141 lines
7.5 KiB
Vue
<template>
|
||
<div>
|
||
<div class="page-header">
|
||
<div><h2>{{ title }}</h2><p>业务伙伴独立于本公司的组织数据,可按合作组织配置{{ title }}身份和状态。</p></div>
|
||
<el-button type="primary" @click="openCreate">新增{{ title }}</el-button>
|
||
</div>
|
||
<div class="filters">
|
||
<el-select v-model="categoryFilter" placeholder="全部业务分类" clearable @change="load(1)">
|
||
<el-option v-for="(label, value) in CATEGORY_LABELS" :key="value" :label="label" :value="value" />
|
||
<el-option label="未分类" value="unclassified" />
|
||
</el-select>
|
||
</div>
|
||
<BaseTable
|
||
:data="rows"
|
||
:loading="loading"
|
||
:empty-text="`暂无${title}`"
|
||
:current-page="pagination.currentPage"
|
||
:page-size="pagination.pageSize"
|
||
:total="pagination.total"
|
||
@page-change="load"
|
||
>
|
||
<el-table-column prop="partner_code" label="伙伴编码" width="140" />
|
||
<el-table-column prop="legal_name" label="企业名称" min-width="180" />
|
||
<el-table-column label="业务分类" min-width="220">
|
||
<template #default="{ row }">
|
||
<template v-if="row[categoriesField]?.length">
|
||
<el-tag v-for="category in row[categoriesField]" :key="category" class="category-tag">{{ CATEGORY_LABELS[category] || category }}</el-tag>
|
||
</template>
|
||
<span v-else class="unclassified">未分类</span>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column prop="unified_credit_code" label="统一社会信用代码" min-width="180" />
|
||
<el-table-column prop="contact_name" label="联系人" width="110" />
|
||
<el-table-column prop="contact_phone" label="联系电话" width="140" />
|
||
<el-table-column :prop="statusField" label="合作状态" width="110" :formatter="statusFormatter" />
|
||
<el-table-column label="操作" width="100"><template #default="{ row }"><el-button link type="primary" @click="openEdit(row)">编辑</el-button></template></el-table-column>
|
||
</BaseTable>
|
||
|
||
<el-dialog v-model="dialogVisible" :title="`${editingId ? '编辑' : '新增'}${title}`" width="560px">
|
||
<el-form :model="form" label-width="130px">
|
||
<el-form-item label="伙伴编码" required><el-input v-model="form.partner_code" :disabled="Boolean(editingId)" /></el-form-item>
|
||
<el-form-item label="企业名称" required><el-input v-model="form.legal_name" /></el-form-item>
|
||
<el-form-item label="业务分类">
|
||
<el-checkbox-group v-model="form[categoriesField]">
|
||
<el-checkbox v-for="(label, value) in CATEGORY_LABELS" :key="value" :value="value">{{ label }}</el-checkbox>
|
||
</el-checkbox-group>
|
||
</el-form-item>
|
||
<el-form-item label="统一社会信用代码"><el-input v-model="form.unified_credit_code" /></el-form-item>
|
||
<el-form-item label="联系人"><el-input v-model="form.contact_name" /></el-form-item>
|
||
<el-form-item label="联系电话"><el-input v-model="form.contact_phone" /></el-form-item>
|
||
<el-form-item label="地址"><el-input v-model="form.address" /></el-form-item>
|
||
<el-form-item label="合作状态">
|
||
<el-select v-model="form.status" style="width: 100%">
|
||
<el-option v-for="(label, value) in STATUS_LABELS" :key="value" :label="label" :value="value" />
|
||
</el-select>
|
||
</el-form-item>
|
||
</el-form>
|
||
<template #footer><el-button @click="dialogVisible = false">取消</el-button><el-button type="primary" :loading="saving" @click="save">保存</el-button></template>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { computed, onMounted, reactive, ref, watch } from 'vue'
|
||
import { ElMessage } from 'element-plus'
|
||
import { partnersApi } from '../../api/partners'
|
||
import { replaceAllKeys } from '../../utils/replaceAllKeys'
|
||
import BaseTable from '../../components/business/BaseTable.vue'
|
||
|
||
const props = defineProps({ role: { type: String, required: true }, title: { type: String, required: true } })
|
||
const rows = ref([])
|
||
const loading = ref(false)
|
||
const saving = ref(false)
|
||
const dialogVisible = ref(false)
|
||
const editingId = ref(null)
|
||
// 每页条数跟物料等列表页保持一致,避免同一个系统里两种翻页手感
|
||
const pagination = reactive({ currentPage: 1, pageSize: 20, total: 0 })
|
||
const statusField = computed(() => `${props.role}_status`)
|
||
const categoriesField = computed(() => `${props.role}_categories`)
|
||
const CATEGORY_LABELS = { material: '物料级(生产)', finished_product: '成品级(经营买卖)' }
|
||
const categoryFilter = ref('')
|
||
// 合作状态英文枚举到中文的对照。列表列与编辑弹窗共用这一份,避免两处各写一遍后失步。
|
||
const STATUS_LABELS = { active: '启用', suspended: '暂停', eliminated: '淘汰', pending: '待审核', inactive: '停用' }
|
||
// 未收录的状态原样显示,不伪装成某个已知状态。
|
||
function statusFormatter(row, column, cellValue) { return STATUS_LABELS[cellValue] || cellValue }
|
||
const form = reactive(emptyForm())
|
||
|
||
function emptyForm() { return { partner_code: '', legal_name: '', unified_credit_code: '', contact_name: '', contact_phone: '', address: '', status: 'active', is_supplier: false, is_customer: false, supplier_categories: [], customer_categories: [] } }
|
||
async function load(currentPage = pagination.currentPage) {
|
||
loading.value = true
|
||
try {
|
||
const offset = (currentPage - 1) * pagination.pageSize
|
||
const params = { limit: pagination.pageSize, offset }
|
||
if (categoryFilter.value) params.category = categoryFilter.value
|
||
const response = await partnersApi.list(props.role, params)
|
||
rows.value = response.data?.items || []
|
||
pagination.total = response.data?.total || 0
|
||
pagination.currentPage = currentPage
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
// 换角色等于换了一份数据集,页码必须归零,否则会停在上一个角色的第 N 页上
|
||
watch(() => props.role, () => { categoryFilter.value = ''; load(1) })
|
||
// 用 replaceAllKeys 而不是 Object.assign:后者删不掉上次编辑残留的 id,
|
||
// 新增时会把别人的 id 一起提交上去。
|
||
function openCreate() { editingId.value = null; replaceAllKeys(form, emptyForm()); dialogVisible.value = true }
|
||
function openEdit(row) {
|
||
editingId.value = row.id
|
||
replaceAllKeys(form, { ...emptyForm(), ...row, status: row[statusField.value] || 'active',
|
||
supplier_categories: [...(row.supplier_categories || [])], customer_categories: [...(row.customer_categories || [])] })
|
||
dialogVisible.value = true
|
||
}
|
||
function payload() {
|
||
return {
|
||
...form,
|
||
is_supplier: form.is_supplier || props.role === 'supplier',
|
||
is_customer: form.is_customer || props.role === 'customer',
|
||
[`${props.role}_status`]: form.status
|
||
}
|
||
}
|
||
async function save() {
|
||
if (!form.partner_code.trim()) { ElMessage.warning('请填写伙伴编码'); return }
|
||
if (!form.legal_name.trim()) { ElMessage.warning('请填写企业名称'); return }
|
||
saving.value = true
|
||
// 保存后停在第几页由 load 的默认参数决定:留在当前页,不把用户甩回第一页
|
||
try { if (editingId.value) await partnersApi.update(editingId.value, payload()); else await partnersApi.create(payload()); ElMessage.success('保存成功'); dialogVisible.value = false; await load() } finally { saving.value = false }
|
||
}
|
||
onMounted(() => load(1))
|
||
</script>
|
||
|
||
<style scoped>
|
||
.page-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; }
|
||
.page-header h2 { margin: 0 0 6px; }
|
||
.page-header p { margin: 0; color: #909399; }
|
||
.filters { margin-bottom: 16px; }
|
||
.filters .el-select { width: 240px; }
|
||
.category-tag { margin-right: 6px; }
|
||
.unclassified { color: #909399; }
|
||
</style>
|