| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- <template>
- <div class="p-2">
- <!-- 入池清单信息 -->
- <el-card shadow="hover" class="mb-[10px]" v-loading="auditInfoLoading">
- <template #header>
- <span class="font-bold">入池清单信息</span>
- </template>
- <el-descriptions :column="3" border>
- <el-descriptions-item label="编号">{{ auditInfo?.id }}</el-descriptions-item>
- <el-descriptions-item label="产品池名称">{{ auditInfo?.poolName || auditInfo?.name }}</el-descriptions-item>
- <el-descriptions-item label="申请时间">{{ auditInfo?.createTime }}</el-descriptions-item>
- <el-descriptions-item label="审核时间">{{ auditInfo?.auditTime || '-' }}</el-descriptions-item>
- <el-descriptions-item label="状态">
- <el-tag :type="getStatusTagType(auditInfo?.productReviewStatus)">{{ getStatusLabel(auditInfo?.productReviewStatus) }}</el-tag>
- </el-descriptions-item>
- <el-descriptions-item label="创建人">{{ auditInfo?.createByName }}</el-descriptions-item>
- <el-descriptions-item label="审核人">{{ auditInfo?.auditByName || '-' }}</el-descriptions-item>
- <el-descriptions-item label="备注">{{ auditInfo?.remark || '-' }}</el-descriptions-item>
- <el-descriptions-item label="驳回意见">{{ auditInfo?.reviewReason || '-' }}</el-descriptions-item>
- </el-descriptions>
- </el-card>
- <!-- 入池清单 -->
- <el-card shadow="never">
- <template #header>
- <span class="font-bold">入池清单</span>
- </template>
- <div class="mb-4" v-if="!auditInfoLoading && !isReadOnly">
- <el-button type="danger" icon="Remove" @click="handleRemoveFromPoolListBatch">移出入池清单</el-button>
- </div>
- <el-table
- ref="poolTableRef"
- v-loading="listLoading"
- :data="poolList"
- border
- @selection-change="handlePoolSelectionChange"
- >
- <el-table-column type="selection" width="55" align="center" />
- <el-table-column type="index" label="序号" width="60" align="center" />
- <el-table-column label="商品编号" align="center" prop="productNo" width="120" />
- <el-table-column label="商品图片" align="center" prop="productImage" width="100">
- <template #default="scope">
- <image-preview :src="scope.row.productImage" :width="60" :height="60"/>
- </template>
- </el-table-column>
- <el-table-column label="商品信息" align="center" min-width="180">
- <template #default="scope">
- <div class="text-left" style="font-size: 12px;">
- <div>{{ scope.row.itemName }}</div>
- <div class="text-gray-500">品牌:{{ scope.row.brandName || '-' }}</div>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="单位" align="center" prop="unitName" width="80" />
- <el-table-column label="SKU价格" align="center" width="150">
- <template #default="scope">
- <div class="text-left" style="font-size: 12px;">
- <div>
- <span class="text-gray-500">市场价:</span>
- <span class="text-red-500">¥{{ scope.row.marketPrice || '0.00' }}</span>
- </div>
- <div>
- <span class="text-gray-500">官网价:</span>
- <span class="text-red-500">¥{{ scope.row.memberPrice || '0.00' }}</span>
- </div>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="成本数据" align="center" width="130">
- <template #default="scope">
- <div class="text-left" style="font-size: 12px;">
- <div>
- <span class="text-gray-500">采购价:</span>
- <span>¥{{ scope.row.purchasePrice || '0.00' }}</span>
- </div>
- </div>
- </template>
- </el-table-column>
- <el-table-column label="项目/平台价" align="center" width="100">
- <template #default="scope">
- <span class="text-red-500">¥{{ scope.row.agreementPrice ?? scope.row.minSellingPrice ?? '0.00' }}</span>
- </template>
- </el-table-column>
- <el-table-column label="商品状态" align="center" width="80">
- <template #default="scope">
- <el-tag v-if="scope.row.productStatus === '1'" type="success">上架</el-tag>
- <el-tag v-else type="warning">下架</el-tag>
- </template>
- </el-table-column>
- <el-table-column label="创建供应商" align="center" width="100">
- <template #default="scope">
- <span>{{ getSupplierName(scope.row.supplier) }}</span>
- </template>
- </el-table-column>
- <el-table-column v-if="!auditInfoLoading && !isReadOnly" label="操作" align="center" width="80" fixed="right">
- <template #default="scope">
- <el-link type="danger" :underline="false" @click="handleRemoveFromPoolList(scope.row)">移除</el-link>
- </template>
- </el-table-column>
- </el-table>
- <pagination
- v-show="listTotal > 0"
- :total="listTotal"
- v-model:page="listQuery.pageNum"
- v-model:limit="listQuery.pageSize"
- @pagination="getPoolList"
- />
- </el-card>
- <!-- 底部操作按钮 -->
- <div v-if="!auditInfoLoading && !isReadOnly" class="fixed bottom-0 left-0 right-0 bg-white border-t p-4 flex justify-center gap-4 z-10">
- <el-button type="danger" size="large" @click="handleReject">驳 回</el-button>
- <el-button type="primary" size="large" @click="handlePass">通 过</el-button>
- </div>
- <!-- 驳回原因对话框 -->
- <el-dialog title="驳回原因" v-model="rejectDialog.visible" width="500px" append-to-body>
- <el-form :model="rejectDialog.form" label-width="80px">
- <el-form-item label="驳回原因" required>
- <el-input
- v-model="rejectDialog.form.reason"
- type="textarea"
- :rows="4"
- placeholder="请输入驳回原因"
- />
- </el-form-item>
- </el-form>
- <template #footer>
- <el-button @click="rejectDialog.visible = false">取 消</el-button>
- <el-button type="primary" @click="confirmReject">确 定</el-button>
- </template>
- </el-dialog>
- </div>
- </template>
- <script setup name="PoolAuditReview" lang="ts">
- import { useRouter, useRoute } from 'vue-router';
- import { getPoolAudit, updatePoolAudit, getPoolAuditProductPage, batchAudit } from '@/api/product/poolAudit';
- import { PoolAuditVO } from '@/api/product/poolAudit/types';
- import { delPoolLinkAudit } from '@/api/product/poolLinkAudit';
- import { PoolLinkVO } from '@/api/product/poolLink/types';
- import { listInfo } from '@/api/customer/supplierInfo';
- import { InfoVO } from '@/api/customer/supplierInfo/types';
- const { proxy } = getCurrentInstance() as ComponentInternalInstance;
- const router = useRouter();
- const route = useRoute();
- const poolAuditId = computed(() => (route.params.id || route.query.id) as string | number);
- // 审核信息
- const auditInfoLoading = ref(false);
- const auditInfo = ref<(PoolAuditVO & { createTime?: string; auditTime?: string }) | undefined>();
- // 入池清单
- const listLoading = ref(false);
- const poolList = ref<PoolLinkVO[]>([]);
- const listTotal = ref(0);
- const listQuery = ref({
- pageNum: 1,
- pageSize: 10
- });
- const selectedPoolProducts = ref<PoolLinkVO[]>([]);
- const poolTableRef = ref<any>();
- // 供应商
- const supplierOptions = ref<InfoVO[]>([]);
- /** 是否只读(审核通过或已驳回状态) */
- const isReadOnly = computed(() => {
- const status = auditInfo.value?.productReviewStatus;
- return status === '2' || status === '3';
- });
- // 驳回对话框
- const rejectDialog = reactive({
- visible: false,
- form: {
- reason: ''
- }
- });
- /** 获取审核状态标签文字 */
- const getStatusLabel = (status?: string): string => {
- const map: Record<string, string> = { '0': '待提交', '1': '待审核', '2': '审核通过', '3': '审核驳回' };
- return status !== undefined ? (map[status] || status) : '-';
- };
- /** 获取审核状态标签类型 */
- const getStatusTagType = (status?: string): 'success' | 'warning' | 'info' | 'danger' | 'primary' => {
- const map: Record<string, 'success' | 'warning' | 'info' | 'danger' | 'primary'> = {
- '0': 'info', '1': 'warning', '2': 'success', '3': 'danger'
- };
- return status !== undefined ? (map[status] || 'primary') : 'primary';
- };
- /** 获取供应商名称 */
- const getSupplierName = (supplierId: string | number | undefined): string => {
- if (!supplierId) return '-';
- const supplier = supplierOptions.value.find(item => item.id === supplierId);
- return supplier?.enterpriseName || supplier?.shortName || '-';
- };
- /** 加载审核信息 */
- const loadAuditInfo = async () => {
- if (!poolAuditId.value) return;
- auditInfoLoading.value = true;
- try {
- const res = await getPoolAudit(poolAuditId.value);
- auditInfo.value = res.data as any;
- } catch (error) {
- console.error('加载审核信息失败:', error);
- } finally {
- auditInfoLoading.value = false;
- }
- };
- /** 获取供应商列表 */
- const getSupplierList = async () => {
- try {
- const res = await listInfo();
- supplierOptions.value = res.data || res.rows || [];
- } catch (error) {
- console.error('获取供应商列表失败:', error);
- }
- };
- /** 获取入池清单列表 */
- const getPoolList = async () => {
- listLoading.value = true;
- try {
- const params = {
- pageNum: listQuery.value.pageNum,
- pageSize: listQuery.value.pageSize,
- poolAuditId: poolAuditId.value
- };
- const res = await getPoolAuditProductPage(params);
- poolList.value = (res.rows || res.data || []) as any;
- listTotal.value = res.total || 0;
- } catch (error) {
- console.error('获取入池清单列表失败:', error);
- poolList.value = [];
- listTotal.value = 0;
- } finally {
- listLoading.value = false;
- }
- };
- /** 入池清单选择变化 */
- const handlePoolSelectionChange = (selection: PoolLinkVO[]) => {
- selectedPoolProducts.value = selection;
- };
- /** 批量移出入池清单 */
- const handleRemoveFromPoolListBatch = async () => {
- if (selectedPoolProducts.value.length === 0) {
- proxy?.$modal.msgWarning('请先选择要移出的商品');
- return;
- }
- await proxy?.$modal.confirm(`确认要将 ${selectedPoolProducts.value.length} 个商品移出入池清单吗?`);
- try {
- const promises = selectedPoolProducts.value.map(item =>
- delPoolLinkAudit((item as any).poolAuditProductId)
- );
- await Promise.all(promises);
- proxy?.$modal.msgSuccess('移出成功');
- selectedPoolProducts.value = [];
- if (poolTableRef.value) {
- poolTableRef.value.clearSelection();
- }
- await getPoolList();
- } catch (error) {
- console.error('移出入池清单失败:', error);
- proxy?.$modal.msgError('移出入池清单失败');
- }
- };
- /** 从入池清单移除单个 */
- const handleRemoveFromPoolList = async (row: PoolLinkVO) => {
- await proxy?.$modal.confirm('确认要从入池清单移除该商品吗?');
- try {
- await delPoolLinkAudit((row as any).poolAuditProductId);
- proxy?.$modal.msgSuccess('移除成功');
- await getPoolList();
- } catch (error) {
- console.error('移除失败:', error);
- proxy?.$modal.msgError('移除失败');
- }
- };
- /** 驳回 */
- const handleReject = () => {
- rejectDialog.form.reason = '';
- rejectDialog.visible = true;
- };
- /** 确认驳回 */
- const confirmReject = async () => {
- if (!rejectDialog.form.reason?.trim()) {
- proxy?.$modal.msgWarning('请输入驳回原因');
- return;
- }
- try {
- await updatePoolAudit({
- id: auditInfo.value?.id,
- productReviewStatus: '3',
- reviewReason: rejectDialog.form.reason
- });
- proxy?.$modal.msgSuccess('驳回成功');
- rejectDialog.visible = false;
- router.back();
- } catch (error) {
- console.error('驳回失败:', error);
- }
- };
- /** 通过 */
- const handlePass = async () => {
- if (poolList.value.length === 0) {
- proxy?.$modal.msgWarning('入池清单为空,请先将商品加入入池清单');
- return;
- }
- await proxy?.$modal.confirm('确认审核通过该入池申请吗?');
- try {
- // 获取入池清单中所有商品的productId
- const productIds = poolList.value.map(item => item.productId);
- // 调用批量审核接口
- await batchAudit({
- poolAuditId: poolAuditId.value,
- productIds: productIds,
- auditStatus: '2' // 审核通过
- });
- proxy?.$modal.msgSuccess('审核通过');
- router.back();
- } catch (error) {
- console.error('审核通过失败:', error);
- }
- };
- onMounted(() => {
- loadAuditInfo();
- getSupplierList();
- getPoolList();
- });
- </script>
- <style scoped lang="scss">
- .p-2 {
- padding-bottom: 80px; // 为底部固定按钮留出空间
- }
- </style>
|