material_manage_system/frontend/src/views/partners/PartnerList.vue

141 lines
7.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>