Merge branch 'master' of http://git.lionquexpress.com/wuweihua/BMS
This commit is contained in:
+5
-1
@@ -81,7 +81,11 @@ public class BmsCustomerController extends BaseController
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody BmsCustomer bmsCustomer)
|
||||
{
|
||||
return toAjax(bmsCustomerService.insertBmsCustomer(bmsCustomer));
|
||||
bmsCustomerService.insertBmsCustomer(bmsCustomer);
|
||||
// 返回新主键,供前端新增成功后停留在编辑页继续维护子表/绑定产品
|
||||
AjaxResult ajax = AjaxResult.success("新增成功");
|
||||
ajax.put("customerId", bmsCustomer.getCustomerId());
|
||||
return ajax;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -84,7 +84,7 @@ public class CustomerMoneyController extends BaseController
|
||||
/**
|
||||
* 审核通过收款单:确认后变动客户余额并生成余额流水
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('customersupplier:customerinfo:edit')")
|
||||
@PreAuthorize("@ss.hasPermi('customer:balance:review')")
|
||||
@Log(title = "客户收款审核", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/receipt/confirm/{id}")
|
||||
public AjaxResult confirmReceipt(@PathVariable("id") Long id)
|
||||
|
||||
+21
-1
@@ -74,7 +74,11 @@ public class BmsSupplierController extends BaseController
|
||||
@PostMapping
|
||||
public AjaxResult add(@RequestBody BmsSupplier bmsSupplier)
|
||||
{
|
||||
return toAjax(bmsSupplierService.insertBmsSupplier(bmsSupplier));
|
||||
bmsSupplierService.insertBmsSupplier(bmsSupplier);
|
||||
// 返回新主键,供前端新增成功后停留在编辑页继续维护子表
|
||||
AjaxResult ajax = AjaxResult.success("新增成功");
|
||||
ajax.put("supplierId", bmsSupplier.getSupplierId());
|
||||
return ajax;
|
||||
}
|
||||
|
||||
/** 修改供应商 */
|
||||
@@ -112,4 +116,20 @@ public class BmsSupplierController extends BaseController
|
||||
List<BmsSupplierCompany> list = bmsSupplierService.selectBmsSupplierCompanyList(bmsSupplierCompany);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
/** 删除供应商公司主体 */
|
||||
@Log(title = "供应商公司主体", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/company/{companyIds}")
|
||||
public AjaxResult removeCompany(@PathVariable Long[] companyIds)
|
||||
{
|
||||
return toAjax(bmsSupplierService.deleteBmsSupplierCompanyByCompanyIds(companyIds));
|
||||
}
|
||||
|
||||
/** 删除供应商联系人 */
|
||||
@Log(title = "供应商联系人", businessType = BusinessType.DELETE)
|
||||
@DeleteMapping("/contact/{contactIds}")
|
||||
public AjaxResult removeContact(@PathVariable Long[] contactIds)
|
||||
{
|
||||
return toAjax(bmsSupplierService.deleteBmsSupplierContactByContactIds(contactIds));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<select id="selectBmsCustomerList" parameterType="BmsCustomer" resultMap="BmsCustomerResult">
|
||||
<include refid="selectBmsCustomerVo"/>
|
||||
<where>
|
||||
c.del_flag = '0'
|
||||
<if test="customerCode != null and customerCode != ''"> and c.customer_code = #{customerCode}</if>
|
||||
<if test="customerName != null and customerName != ''"> and c.customer_name like concat('%', #{customerName}, '%')</if>
|
||||
<if test="customerCodeDw != null and customerCodeDw != ''"> and c.customer_code_dw = #{customerCodeDw}</if>
|
||||
@@ -265,14 +266,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="creditCode != null">credit_code = #{creditCode},</if>
|
||||
<if test="customerType != null">customer_type = #{customerType},</if>
|
||||
<if test="isEnable != null">is_enable = #{isEnable},</if>
|
||||
<if test="salesUserId != null">sales_user_id = #{salesUserId},</if>
|
||||
<if test="salesUser != null">sales_user = #{salesUser},</if>
|
||||
sales_user_id = #{salesUserId},
|
||||
sales_user = #{salesUser},
|
||||
<if test="ed != null">ed = #{ed},</if>
|
||||
<if test="zq != null">zq = #{zq},</if>
|
||||
<if test="settlementUserId != null">settlement_user_id = #{settlementUserId},</if>
|
||||
<if test="settlementUser != null">settlement_user = #{settlementUser},</if>
|
||||
<if test="serviceUserId != null">service_user_id = #{serviceUserId},</if>
|
||||
<if test="serviceUser != null">service_user = #{serviceUser},</if>
|
||||
settlement_user_id = #{settlementUserId},
|
||||
settlement_user = #{settlementUser},
|
||||
service_user_id = #{serviceUserId},
|
||||
service_user = #{serviceUser},
|
||||
<if test="settlementType != null">settlement_type = #{settlementType},</if>
|
||||
<if test="tempEd != null">temp_ed = #{tempEd},</if>
|
||||
<if test="accountBalance != null">account_balance = #{accountBalance},</if>
|
||||
|
||||
@@ -139,12 +139,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="creditCode != null">credit_code = #{creditCode},</if>
|
||||
<if test="supplierType != null">supplier_type = #{supplierType},</if>
|
||||
<if test="isEnable != null">is_enable = #{isEnable},</if>
|
||||
<if test="purchaserUserId != null">purchaser_user_id = #{purchaserUserId},</if>
|
||||
<if test="purchaserUser != null">purchaser_user = #{purchaserUser},</if>
|
||||
<if test="settlementUserId != null">settlement_user_id = #{settlementUserId},</if>
|
||||
<if test="settlementUser != null">settlement_user = #{settlementUser},</if>
|
||||
<if test="serviceUserId != null">service_user_id = #{serviceUserId},</if>
|
||||
<if test="serviceUser != null">service_user = #{serviceUser},</if>
|
||||
purchaser_user_id = #{purchaserUserId},
|
||||
purchaser_user = #{purchaserUser},
|
||||
settlement_user_id = #{settlementUserId},
|
||||
settlement_user = #{settlementUser},
|
||||
service_user_id = #{serviceUserId},
|
||||
service_user = #{serviceUser},
|
||||
<if test="ed != null">ed = #{ed},</if>
|
||||
<if test="zq != null">zq = #{zq},</if>
|
||||
<if test="settlementType != null">settlement_type = #{settlementType},</if>
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
-- ----------------------------
|
||||
-- 客户管理 / 供应商管理 菜单按钮权限补全 + 普通角色(role_id=2)初始授权
|
||||
-- 幂等:可重复执行;已有记录不会重复插入
|
||||
-- 菜单结构:
|
||||
-- 2309 客户/供应商管理(M)
|
||||
-- 2313 客户管理(C) perms -> customersupplier:customerinfo:list
|
||||
-- 2422 客户余额管理(C,隐藏,静态路由页面,仅作收款审核按钮挂载点)
|
||||
-- 2423 收款审核(F) customer:balance:review
|
||||
-- [新增] 客户查询/新增/修改/删除/导出 5个F按钮
|
||||
-- 2314 供应商管理(C) perms -> customersupplier:supplierinfo:list
|
||||
-- [新增] 供应商查询/新增/修改/删除/导出 5个F按钮
|
||||
-- ----------------------------
|
||||
|
||||
-- 1. 两个业务菜单补 list 权限标识(后端列表接口 @PreAuthorize 要求)
|
||||
UPDATE `sys_menu` SET `perms` = 'customersupplier:customerinfo:list'
|
||||
WHERE `menu_id` = 2313 AND (`perms` IS NULL OR `perms` = '');
|
||||
|
||||
UPDATE `sys_menu` SET `perms` = 'customersupplier:supplierinfo:list'
|
||||
WHERE `menu_id` = 2314 AND (`perms` IS NULL OR `perms` = '');
|
||||
|
||||
-- 2. 客户余额管理为静态路由页面(/customersupplier/customer-money),侧边栏不应显示,避免死链
|
||||
UPDATE `sys_menu` SET `visible` = '1'
|
||||
WHERE `menu_id` = 2422 AND `visible` = '0';
|
||||
|
||||
-- 3. 补全客户管理 5 个按钮(F),按 perms 幂等
|
||||
INSERT INTO `sys_menu`
|
||||
(`menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`,
|
||||
`menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `remark`)
|
||||
SELECT '客户查询', 2313, 1, '', '', '', 1, 0, 'F', '0', '0', 'customersupplier:customerinfo:query', '#', 'admin', NOW(), ''
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `perms` = 'customersupplier:customerinfo:query' AND `parent_id` = 2313);
|
||||
|
||||
INSERT INTO `sys_menu`
|
||||
(`menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`,
|
||||
`menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `remark`)
|
||||
SELECT '客户新增', 2313, 2, '', '', '', 1, 0, 'F', '0', '0', 'customersupplier:customerinfo:add', '#', 'admin', NOW(), ''
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `perms` = 'customersupplier:customerinfo:add' AND `parent_id` = 2313);
|
||||
|
||||
INSERT INTO `sys_menu`
|
||||
(`menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`,
|
||||
`menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `remark`)
|
||||
SELECT '客户修改', 2313, 3, '', '', '', 1, 0, 'F', '0', '0', 'customersupplier:customerinfo:edit', '#', 'admin', NOW(), ''
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `perms` = 'customersupplier:customerinfo:edit' AND `parent_id` = 2313);
|
||||
|
||||
INSERT INTO `sys_menu`
|
||||
(`menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`,
|
||||
`menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `remark`)
|
||||
SELECT '客户删除', 2313, 4, '', '', '', 1, 0, 'F', '0', '0', 'customersupplier:customerinfo:remove', '#', 'admin', NOW(), ''
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `perms` = 'customersupplier:customerinfo:remove' AND `parent_id` = 2313);
|
||||
|
||||
INSERT INTO `sys_menu`
|
||||
(`menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`,
|
||||
`menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `remark`)
|
||||
SELECT '客户导出', 2313, 5, '', '', '', 1, 0, 'F', '0', '0', 'customersupplier:customerinfo:export', '#', 'admin', NOW(), ''
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `perms` = 'customersupplier:customerinfo:export' AND `parent_id` = 2313);
|
||||
|
||||
-- 4. 补全供应商管理 5 个按钮(F),按 perms 幂等
|
||||
INSERT INTO `sys_menu`
|
||||
(`menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`,
|
||||
`menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `remark`)
|
||||
SELECT '供应商查询', 2314, 1, '', '', '', 1, 0, 'F', '0', '0', 'customersupplier:supplierinfo:query', '#', 'admin', NOW(), ''
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `perms` = 'customersupplier:supplierinfo:query' AND `parent_id` = 2314);
|
||||
|
||||
INSERT INTO `sys_menu`
|
||||
(`menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`,
|
||||
`menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `remark`)
|
||||
SELECT '供应商新增', 2314, 2, '', '', '', 1, 0, 'F', '0', '0', 'customersupplier:supplierinfo:add', '#', 'admin', NOW(), ''
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `perms` = 'customersupplier:supplierinfo:add' AND `parent_id` = 2314);
|
||||
|
||||
INSERT INTO `sys_menu`
|
||||
(`menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`,
|
||||
`menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `remark`)
|
||||
SELECT '供应商修改', 2314, 3, '', '', '', 1, 0, 'F', '0', '0', 'customersupplier:supplierinfo:edit', '#', 'admin', NOW(), ''
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `perms` = 'customersupplier:supplierinfo:edit' AND `parent_id` = 2314);
|
||||
|
||||
INSERT INTO `sys_menu`
|
||||
(`menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`,
|
||||
`menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `remark`)
|
||||
SELECT '供应商删除', 2314, 4, '', '', '', 1, 0, 'F', '0', '0', 'customersupplier:supplierinfo:remove', '#', 'admin', NOW(), ''
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `perms` = 'customersupplier:supplierinfo:remove' AND `parent_id` = 2314);
|
||||
|
||||
INSERT INTO `sys_menu`
|
||||
(`menu_name`, `parent_id`, `order_num`, `path`, `component`, `query`, `is_frame`, `is_cache`,
|
||||
`menu_type`, `visible`, `status`, `perms`, `icon`, `create_by`, `create_time`, `remark`)
|
||||
SELECT '供应商导出', 2314, 5, '', '', '', 1, 0, 'F', '0', '0', 'customersupplier:supplierinfo:export', '#', 'admin', NOW(), ''
|
||||
WHERE NOT EXISTS (SELECT 1 FROM `sys_menu` WHERE `perms` = 'customersupplier:supplierinfo:export' AND `parent_id` = 2314);
|
||||
|
||||
-- 5. 普通角色(role_id=2) 授权:目录 + 2个菜单 + 余额隐藏菜单 + 收款审核 + 10个新按钮(幂等)
|
||||
INSERT INTO `sys_role_menu` (`role_id`, `menu_id`)
|
||||
SELECT 2, m.`menu_id`
|
||||
FROM `sys_menu` m
|
||||
WHERE (
|
||||
m.`menu_id` IN (2309, 2313, 2314, 2422, 2423)
|
||||
OR m.`perms` IN (
|
||||
'customersupplier:customerinfo:query', 'customersupplier:customerinfo:add',
|
||||
'customersupplier:customerinfo:edit', 'customersupplier:customerinfo:remove',
|
||||
'customersupplier:customerinfo:export',
|
||||
'customersupplier:supplierinfo:query', 'customersupplier:supplierinfo:add',
|
||||
'customersupplier:supplierinfo:edit', 'customersupplier:supplierinfo:remove',
|
||||
'customersupplier:supplierinfo:export'
|
||||
)
|
||||
)
|
||||
AND NOT EXISTS (
|
||||
SELECT 1 FROM `sys_role_menu` rm WHERE rm.`role_id` = 2 AND rm.`menu_id` = m.`menu_id`
|
||||
);
|
||||
@@ -42,3 +42,19 @@ export function delCustomer(customerId) {
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 删除客户公司主体
|
||||
export function delCustomerCompany(companyId) {
|
||||
return request({
|
||||
url: '/customersupplier/customerinfo/company/' + companyId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 删除客户联系人
|
||||
export function delCustomerContact(contactId) {
|
||||
return request({
|
||||
url: '/customersupplier/customerinfo/contact/' + contactId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -42,3 +42,19 @@ export function delSupplier(supplierId) {
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 删除供应商公司主体
|
||||
export function delSupplierCompany(companyId) {
|
||||
return request({
|
||||
url: '/customersupplier/supplierinfo/company/' + companyId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
// 删除供应商联系人
|
||||
export function delSupplierContact(contactId) {
|
||||
return request({
|
||||
url: '/customersupplier/supplierinfo/contact/' + contactId,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
<template>
|
||||
<div class="product-select">
|
||||
<el-button type="primary" plain icon="Connection" @click="openDialog">
|
||||
{{ selectedIds.length ? '重新选择产品' : '选择产品' }}
|
||||
</el-button>
|
||||
<span class="ps-summary">
|
||||
已绑定 <b>{{ selectedIds.length }}</b> 个产品
|
||||
<el-button v-if="selectedIds.length" link type="danger" @click="clearSelection">清空</el-button>
|
||||
</span>
|
||||
|
||||
<el-dialog
|
||||
v-model="dialogVisible"
|
||||
title="选择绑定产品"
|
||||
width="960px"
|
||||
append-to-body
|
||||
:close-on-click-modal="false"
|
||||
@open="handleOpen"
|
||||
>
|
||||
<el-form :inline="true" class="ps-filter" @submit.prevent>
|
||||
<el-form-item label="产品代码">
|
||||
<el-input v-model="queryParams.productCode" placeholder="如 WSP037" clearable style="width: 150px" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="产品名称">
|
||||
<el-input v-model="queryParams.productName" placeholder="产品名称" clearable style="width: 160px" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="目的区域">
|
||||
<el-input v-model="queryParams.destRegion" placeholder="如 欧盟" clearable style="width: 120px" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="走货属性">
|
||||
<el-input v-model="queryParams.cargoAttr" placeholder="普货/带电等" clearable style="width: 120px" @keyup.enter="handleQuery" />
|
||||
</el-form-item>
|
||||
<el-form-item label="状态">
|
||||
<el-select v-model="queryParams.status" placeholder="全部" clearable style="width: 110px">
|
||||
<el-option label="待生效" value="0" />
|
||||
<el-option label="已生效" value="1" />
|
||||
<el-option label="已失效" value="2" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
|
||||
<el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-table
|
||||
ref="tableRef"
|
||||
v-loading="loading"
|
||||
:data="filteredList"
|
||||
row-key="productId"
|
||||
height="380"
|
||||
border
|
||||
@select="handleSelect"
|
||||
@select-all="handleSelectAll"
|
||||
>
|
||||
<el-table-column type="selection" width="48" align="center" />
|
||||
<el-table-column label="产品代码" prop="productCode" width="110" show-overflow-tooltip />
|
||||
<el-table-column label="产品名称" prop="productName" min-width="160" show-overflow-tooltip />
|
||||
<el-table-column label="时效等级" prop="serviceLevel" width="90" show-overflow-tooltip />
|
||||
<el-table-column label="走货属性" prop="cargoAttr" width="90" show-overflow-tooltip />
|
||||
<el-table-column label="目的区域" prop="destRegion" width="90" show-overflow-tooltip />
|
||||
<el-table-column label="包税" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag v-if="row.taxMode === 'TAX_INCLUDED'" type="success" size="small">包税</el-tag>
|
||||
<el-tag v-else-if="row.taxMode === 'TAX_EXCLUDED'" type="warning" size="small">不包税</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="80" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="statusTagType[row.status] || 'info'" size="small">{{ statusMap[row.status] || '未知' }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<div slot="empty" class="ps-empty">暂无产品数据</div>
|
||||
</el-table>
|
||||
|
||||
<template #footer>
|
||||
<div class="ps-footer">
|
||||
<span>已选 <b>{{ draftIds.size }}</b> 个产品</span>
|
||||
<div>
|
||||
<el-button @click="dialogVisible = false">取消</el-button>
|
||||
<el-button type="primary" @click="confirmSelection">确定</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup name="ProductSelect">
|
||||
import { ref, reactive, computed, watch, nextTick } from 'vue'
|
||||
import { useProducts } from './useProducts'
|
||||
|
||||
const props = defineProps({
|
||||
/** v-model 绑定值:逗号分隔的产品ID串,如 "3,6" */
|
||||
modelValue: { type: [String, Number], default: '' }
|
||||
})
|
||||
const emit = defineEmits(['update:modelValue', 'change'])
|
||||
|
||||
const { productList, ensureProducts } = useProducts()
|
||||
|
||||
const dialogVisible = ref(false)
|
||||
const loading = ref(false)
|
||||
const tableRef = ref(null)
|
||||
const draftIds = reactive(new Set())
|
||||
const queryParams = reactive({
|
||||
productCode: '',
|
||||
productName: '',
|
||||
destRegion: '',
|
||||
cargoAttr: '',
|
||||
status: ''
|
||||
})
|
||||
|
||||
const selectedIds = computed(() =>
|
||||
String(props.modelValue || '').split(',').map(s => s.trim()).filter(Boolean)
|
||||
)
|
||||
|
||||
const statusMap = { 0: '待生效', 1: '已生效', 2: '已失效' }
|
||||
const statusTagType = { 0: 'info', 1: 'success', 2: 'danger' }
|
||||
|
||||
const filteredList = computed(() => {
|
||||
return productList.value.filter(p => {
|
||||
if (queryParams.productCode && !(p.productCode || '').toLowerCase().includes(queryParams.productCode.trim().toLowerCase())) return false
|
||||
if (queryParams.productName && !(p.productName || '').includes(queryParams.productName.trim())) return false
|
||||
if (queryParams.destRegion && !(p.destRegion || '').includes(queryParams.destRegion.trim())) return false
|
||||
if (queryParams.cargoAttr && !(p.cargoAttr || '').includes(queryParams.cargoAttr.trim())) return false
|
||||
if (queryParams.status !== '' && queryParams.status !== null && queryParams.status !== undefined && String(p.status) !== String(queryParams.status)) return false
|
||||
return true
|
||||
})
|
||||
})
|
||||
|
||||
function openDialog() {
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
function handleOpen() {
|
||||
loading.value = true
|
||||
draftIds.clear()
|
||||
selectedIds.value.forEach(id => draftIds.add(id))
|
||||
resetQuery(false)
|
||||
// 拉取最新产品后,按 draftIds 全量同步一次勾选(覆盖上次弹窗遗留状态)
|
||||
ensureProducts(true).finally(() => {
|
||||
loading.value = false
|
||||
nextTick(syncSelection)
|
||||
})
|
||||
}
|
||||
|
||||
/** 按 draftIds 同步当前渲染行的勾选状态(draftIds 为唯一数据源,筛选切换不丢选择) */
|
||||
function syncSelection() {
|
||||
if (!tableRef.value) return
|
||||
filteredList.value.forEach(row => {
|
||||
tableRef.value.toggleRowSelection(row, draftIds.has(String(row.productId)))
|
||||
})
|
||||
}
|
||||
|
||||
/** 数据/筛选变化后同步表格勾选状态 */
|
||||
watch(filteredList, () => {
|
||||
if (!dialogVisible.value) return
|
||||
nextTick(syncSelection)
|
||||
}, { flush: 'post' })
|
||||
|
||||
function handleSelect(selection, row) {
|
||||
const id = String(row.productId)
|
||||
if (draftIds.has(id)) draftIds.delete(id)
|
||||
else draftIds.add(id)
|
||||
}
|
||||
|
||||
function handleSelectAll(selection) {
|
||||
// selection 为当前过滤后页面被选中的行;长度>0 表示全选,否则取消全选
|
||||
if (selection.length) {
|
||||
filteredList.value.forEach(row => draftIds.add(String(row.productId)))
|
||||
} else {
|
||||
filteredList.value.forEach(row => draftIds.delete(String(row.productId)))
|
||||
}
|
||||
}
|
||||
|
||||
function handleQuery() {
|
||||
// 纯前端过滤(全量已缓存),watch filteredList 自动同步勾选
|
||||
}
|
||||
|
||||
function resetQuery(reload = true) {
|
||||
queryParams.productCode = ''
|
||||
queryParams.productName = ''
|
||||
queryParams.destRegion = ''
|
||||
queryParams.cargoAttr = ''
|
||||
queryParams.status = ''
|
||||
if (reload) ensureProducts(true)
|
||||
}
|
||||
|
||||
function confirmSelection() {
|
||||
const ids = Array.from(draftIds)
|
||||
const value = ids.join(',')
|
||||
emit('update:modelValue', value)
|
||||
emit('change', ids)
|
||||
dialogVisible.value = false
|
||||
}
|
||||
|
||||
function clearSelection() {
|
||||
emit('update:modelValue', '')
|
||||
emit('change', [])
|
||||
}
|
||||
|
||||
/** 供父组件预加载产品缓存(tab 内明细表格使用) */
|
||||
defineExpose({ ensureProducts })
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.product-select {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
.ps-summary {
|
||||
color: #606266;
|
||||
font-size: 14px;
|
||||
}
|
||||
.ps-summary b {
|
||||
color: #409eff;
|
||||
font-size: 15px;
|
||||
margin: 0 2px;
|
||||
}
|
||||
.ps-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.ps-footer b {
|
||||
color: #409eff;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,67 @@
|
||||
import { ref } from 'vue'
|
||||
import { listProduct } from '@/api/price/product'
|
||||
|
||||
/**
|
||||
* 产品列表模块级共享缓存:全应用只拉取一次
|
||||
* 用于客户绑定产品的选择与已绑产品名称/明细回显
|
||||
*/
|
||||
const productList = ref([])
|
||||
let loadingPromise = null
|
||||
|
||||
/** 逗号分隔 id 串 -> 字符串 id 数组 */
|
||||
export function parseProductIds(value) {
|
||||
if (Array.isArray(value)) return value.map(v => String(v)).filter(Boolean)
|
||||
if (value === null || value === undefined) return []
|
||||
return String(value).split(',').map(s => s.trim()).filter(Boolean)
|
||||
}
|
||||
|
||||
/** id 数组 -> 逗号分隔串(去重,保持原顺序) */
|
||||
export function joinProductIds(ids) {
|
||||
const seen = new Set()
|
||||
const out = []
|
||||
;(ids || []).forEach(id => {
|
||||
const key = String(id)
|
||||
if (key && !seen.has(key)) {
|
||||
seen.add(key)
|
||||
out.push(key)
|
||||
}
|
||||
})
|
||||
return out.join(',')
|
||||
}
|
||||
|
||||
export function useProducts() {
|
||||
/** 确保产品列表已加载(force=true 强制刷新),拉取全部状态以便回显已失效产品 */
|
||||
function ensureProducts(force = false) {
|
||||
if (!force && loadingPromise) return loadingPromise
|
||||
if (!force && productList.value.length) return Promise.resolve(productList.value)
|
||||
loadingPromise = listProduct({ pageNum: 1, pageSize: 1000 })
|
||||
.then(res => {
|
||||
productList.value = res.rows || []
|
||||
return productList.value
|
||||
})
|
||||
.finally(() => {
|
||||
loadingPromise = null
|
||||
})
|
||||
return loadingPromise
|
||||
}
|
||||
|
||||
/** 按产品ID查产品对象 */
|
||||
function findProduct(productId) {
|
||||
if (productId === null || productId === undefined || productId === '') return null
|
||||
return productList.value.find(p => String(p.productId) === String(productId)) || null
|
||||
}
|
||||
|
||||
/** 产品展示名:代码 + 名称 */
|
||||
function getProductLabel(productId) {
|
||||
const p = findProduct(productId)
|
||||
if (!p) return String(productId)
|
||||
return p.productCode + ' ' + p.productName
|
||||
}
|
||||
|
||||
return {
|
||||
productList,
|
||||
ensureProducts,
|
||||
findProduct,
|
||||
getProductLabel
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<template>{{ displayName }}</template>
|
||||
|
||||
<script setup name="UserName">
|
||||
import { computed, onMounted } from 'vue'
|
||||
import { useUsers } from '@/components/UserSelect/useUsers'
|
||||
|
||||
const props = defineProps({
|
||||
/** 用户ID */
|
||||
userId: {
|
||||
type: [String, Number],
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
const { ensureUsers, getUserName } = useUsers()
|
||||
|
||||
// getUserName 内部读取共享 userList,列表加载完成后计算属性自动刷新
|
||||
const displayName = computed(() => getUserName(props.userId))
|
||||
|
||||
onMounted(() => {
|
||||
ensureUsers()
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,110 @@
|
||||
<template>
|
||||
<el-select
|
||||
v-model="innerValue"
|
||||
:placeholder="placeholder"
|
||||
:clearable="clearable"
|
||||
:filterable="filterable"
|
||||
:disabled="disabled"
|
||||
:loading="loading"
|
||||
:size="size"
|
||||
:multiple="false"
|
||||
value-on-clear="null"
|
||||
style="width: 100%;"
|
||||
@change="handleChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in options"
|
||||
:key="item.userId"
|
||||
:label="item.nickName || item.userName"
|
||||
:value="String(item.userId)"
|
||||
>
|
||||
<span>{{ item.nickName || item.userName }}</span>
|
||||
<span
|
||||
v-if="showCode && item.userName"
|
||||
class="user-select-sub"
|
||||
>{{ item.userName }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</template>
|
||||
|
||||
<script setup name="UserSelect">
|
||||
import { computed, onMounted, ref, watch } from 'vue'
|
||||
import { useUsers } from './useUsers'
|
||||
|
||||
const props = defineProps({
|
||||
/** 绑定值:用户ID(字符串/数字),清空时为 null */
|
||||
modelValue: {
|
||||
type: [String, Number],
|
||||
default: null
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: '请选择用户'
|
||||
},
|
||||
clearable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
filterable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
/** 选项右侧是否显示登录账号 */
|
||||
showCode: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['update:modelValue', 'change'])
|
||||
|
||||
const { userList, ensureUsers, findUser } = useUsers()
|
||||
const loading = ref(false)
|
||||
const innerValue = ref(props.modelValue === null || props.modelValue === undefined ? null : String(props.modelValue))
|
||||
|
||||
watch(() => props.modelValue, (val) => {
|
||||
innerValue.value = val === null || val === undefined || val === '' ? null : String(val)
|
||||
})
|
||||
|
||||
/** 兜底:当前值在用户列表中不存在(停用/未加载到)时补占位项,避免显示空白 */
|
||||
const options = computed(() => {
|
||||
const list = userList.value
|
||||
if (innerValue.value && !findUser(innerValue.value)) {
|
||||
return [{ userId: innerValue.value, userName: '', nickName: String(innerValue.value) }, ...list]
|
||||
}
|
||||
return list
|
||||
})
|
||||
|
||||
function handleChange(val) {
|
||||
const value = val === '' ? null : val
|
||||
emit('update:modelValue', value)
|
||||
emit('change', value, value === null ? null : findUser(value))
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loading.value = true
|
||||
ensureUsers().finally(() => {
|
||||
loading.value = false
|
||||
})
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
reload: () => ensureUsers(true)
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.user-select-sub {
|
||||
float: right;
|
||||
color: var(--el-text-color-secondary);
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,45 @@
|
||||
import { ref } from 'vue'
|
||||
import { listUser } from '@/api/system/user'
|
||||
|
||||
/**
|
||||
* 用户列表模块级共享缓存:整个应用只拉取一次,UserSelect / UserName 共用
|
||||
*/
|
||||
const userList = ref([])
|
||||
let loadingPromise = null
|
||||
|
||||
export function useUsers() {
|
||||
/** 确保用户列表已加载(force=true 强制刷新) */
|
||||
function ensureUsers(force = false) {
|
||||
if (!force && loadingPromise) return loadingPromise
|
||||
if (!force && userList.value.length) return Promise.resolve(userList.value)
|
||||
loadingPromise = listUser({ pageNum: 1, pageSize: 1000 })
|
||||
.then(res => {
|
||||
userList.value = res.rows || []
|
||||
return userList.value
|
||||
})
|
||||
.finally(() => {
|
||||
loadingPromise = null
|
||||
})
|
||||
return loadingPromise
|
||||
}
|
||||
|
||||
/** 按用户ID查用户对象 */
|
||||
function findUser(userId) {
|
||||
if (userId === null || userId === undefined || userId === '') return null
|
||||
return userList.value.find(u => String(u.userId) === String(userId)) || null
|
||||
}
|
||||
|
||||
/** 按用户ID取显示名(nickName 优先,找不到时回退显示ID本身) */
|
||||
function getUserName(userId) {
|
||||
if (userId === null || userId === undefined || userId === '') return ''
|
||||
const user = findUser(userId)
|
||||
return user ? (user.nickName || user.userName || String(userId)) : String(userId)
|
||||
}
|
||||
|
||||
return {
|
||||
userList,
|
||||
ensureUsers,
|
||||
findUser,
|
||||
getUserName
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,11 @@ import BasicTable from '@/components/BasicTable'
|
||||
import SimpleTable from '@/components/SimpleTable'
|
||||
// 客户/供应商下拉选择组件
|
||||
import CustomerSelect from '@/components/CustomerSelect'
|
||||
// 用户选择/用户名称展示组件
|
||||
import UserSelect from '@/components/UserSelect'
|
||||
import UserName from '@/components/UserName'
|
||||
// 产品多选绑定组件
|
||||
import ProductSelect from '@/components/ProductSelect'
|
||||
|
||||
const app = createApp(App)
|
||||
|
||||
@@ -76,6 +81,9 @@ app.component('BasicForm', BasicForm)
|
||||
app.component('BasicTable', BasicTable)
|
||||
app.component('SimpleTable', SimpleTable)
|
||||
app.component('CustomerSelect', CustomerSelect)
|
||||
app.component('UserSelect', UserSelect)
|
||||
app.component('UserName', UserName)
|
||||
app.component('ProductSelect', ProductSelect)
|
||||
|
||||
app.use(router)
|
||||
app.use(store)
|
||||
|
||||
@@ -169,7 +169,35 @@ export const dynamicRoutes = [
|
||||
path: 'index',
|
||||
component: () => import('@/views/customersuppliermanagement/customerinfo/customermoney/index.vue'),
|
||||
name: 'CustomerMoney',
|
||||
meta: { title: '客户余额', activeMenu: '/customersupplier/customerinfo' }
|
||||
meta: { title: '客户余额', activeMenu: '/customersuppliermanagement/customerinfo' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/customersupplier/customer-edit',
|
||||
component: Layout,
|
||||
hidden: true,
|
||||
permissions: ['customersupplier:customerinfo:list'],
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
component: () => import('@/views/customersuppliermanagement/customerinfo/customeredit/index.vue'),
|
||||
name: 'CustomerEdit',
|
||||
meta: { title: '客户编辑', activeMenu: '/customersuppliermanagement/customerinfo' }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/customersupplier/supplier-edit',
|
||||
component: Layout,
|
||||
hidden: true,
|
||||
permissions: ['customersupplier:supplierinfo:list'],
|
||||
children: [
|
||||
{
|
||||
path: 'index',
|
||||
component: () => import('@/views/customersuppliermanagement/supplierinfo/supplieredit/index.vue'),
|
||||
name: 'SupplierEdit',
|
||||
meta: { title: '供应商编辑', activeMenu: '/customersuppliermanagement/supplierinfo' }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -84,7 +84,8 @@
|
||||
<el-form-item>
|
||||
<el-button type="primary" icon="Search" @click="getReceiptList">搜索</el-button>
|
||||
<el-button icon="Refresh" @click="resetReceiptQuery">重置</el-button>
|
||||
<el-button type="success" icon="Plus" @click="handleAddReceipt">登记收款</el-button>
|
||||
<el-button type="success" icon="Plus" @click="handleAddReceipt"
|
||||
v-hasPermi="['customersupplier:customerinfo:add']">登记收款</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
@@ -132,9 +133,9 @@
|
||||
<el-table-column label="登记人" align="center" prop="createBy" width="100" />
|
||||
<el-table-column label="操作" align="center" width="200" fixed="right">
|
||||
<template #default="scope">
|
||||
<el-button v-if="scope.row.status === 'PENDING'" link type="success" size="small" @click="handleConfirmReceipt(scope.row)">审核通过</el-button>
|
||||
<el-button v-if="scope.row.status === 'PENDING'" link type="warning" size="small" @click="handleCancelReceipt(scope.row)">取消</el-button>
|
||||
<el-button link type="primary" size="small" @click="handleViewReceipt(scope.row)">查看</el-button>
|
||||
<el-button v-if="scope.row.status === 'PENDING'" link type="success" size="small" @click="handleConfirmReceipt(scope.row)" v-hasPermi="['customer:balance:review']">审核通过</el-button>
|
||||
<el-button v-if="scope.row.status === 'PENDING'" link type="warning" size="small" @click="handleCancelReceipt(scope.row)" v-hasPermi="['customersupplier:customerinfo:edit']">取消</el-button>
|
||||
<el-button link type="primary" size="small" @click="handleViewReceipt(scope.row)" v-hasPermi="['customersupplier:customerinfo:query']">查看</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -392,6 +393,7 @@
|
||||
v-if="viewDialog.data && viewDialog.data.status === 'PENDING'"
|
||||
type="success"
|
||||
@click="handleConfirmFromView"
|
||||
v-hasPermi="['customer:balance:review']"
|
||||
>审核通过</el-button>
|
||||
<el-button @click="viewDialog.visible = false">关 闭</el-button>
|
||||
</template>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user