| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571 |
- <template>
- <div class="p-2">
- <!-- 页面标题 -->
- <el-card shadow="never" class="mb-2">
- <div class="flex justify-between items-center">
- <div class="flex items-center">
- <el-button link @click="handleBack" class="mr-2">
- <el-icon class="mr-1"><ArrowLeft /></el-icon>
- 返回
- </el-button>
- <span class="text-lg font-bold">{{ pageTitle }}</span>
- </div>
- <el-button type="primary" @click="submitForm" :loading="buttonLoading">保存</el-button>
- </div>
- </el-card>
- <!-- 基本信息 -->
- <el-card shadow="never" class="mb-2">
- <el-form ref="revenueHeaderFormRef" :model="form" :rules="rules" label-width="120px">
- <el-row :gutter="20" v-if="form.revenueType == '0'">
- <el-col :span="8">
- <el-form-item label="客户编号:" prop="customerCode">
- <el-select
- v-model="form.customerCode"
- placeholder="请输入客户编号"
- style="width: 100%"
- filterable
- remote
- :remote-method="handleSearchCustomer"
- :loading="customerSearchLoading"
- @change="handleCustomerChange"
- clearable
- >
- <el-option
- v-for="customer in filteredCustomerList"
- :key="customer.id"
- :label="`${customer.customerNo} - ${customer.customerName}`"
- :value="customer.customerNo"
- />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="收入单类型:" prop="revenueType">
- <el-select v-model="form.revenueType" placeholder="请选择" style="width: 100%" disabled>
- <el-option v-for="dict in revenue_type" :key="dict.value" :label="dict.label" :value="dict.value" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="所属公司:" prop="companyName">
- <el-input v-model="form.companyName" disabled />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20" v-if="form.revenueType == '1'">
- <el-col :span="8">
- <el-form-item label="收入单类型:" prop="revenueType">
- <el-select v-model="form.revenueType" placeholder="请选择" style="width: 100%" disabled>
- <el-option v-for="dict in revenue_type" :key="dict.value" :label="dict.label" :value="dict.value" />
- </el-select>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="所属公司:" prop="companyName">
- <el-input v-model="form.companyName" disabled />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="供应商:" prop="supplierName">
- <el-select
- v-model="form.supplierName"
- placeholder="请输入供应商名称"
- style="width: 100%"
- filterable
- remote
- :remote-method="handleSearchCustomer"
- :loading="customerSearchLoading"
- @change="handleCustomerChange"
- clearable
- >
- <el-option
- v-for="customer in filteredCustomerList"
- :key="customer.id"
- :label="`${customer.customerNo} - ${customer.customerName}`"
- :value="customer.customerNo"
- />
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="8">
- <el-form-item label="业务部门:" prop="businessDept">
- <el-input v-model="form.businessDept" disabled />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="客服人员:" prop="customerService">
- <el-input v-model="form.customerService" disabled />
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="业务员:" prop="businessStaff">
- <el-input v-model="form.businessStaff" disabled />
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="8">
- <el-form-item label="是否含税:" prop="isPrwTax">
- <el-radio-group v-model="form.isPrwTax">
- <el-radio v-for="dict in sys_platform_yes_no" :key="dict.value" :value="dict.value">{{ dict.label }}</el-radio>
- </el-radio-group>
- </el-form-item>
- </el-col>
- <el-col :span="8">
- <el-form-item label="交易币别:" prop="currencyId">
- <el-select v-model="form.currencyId" placeholder="请选择" style="width: 100%" clearable>
- <el-option v-for="currency in currencyList" :key="currency.id" :label="currency.currencyName" :value="currency.id" />
- </el-select>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row :gutter="20">
- <el-col :span="16">
- <el-form-item label="备注:" prop="remark">
- <el-input v-model="form.remark" type="textarea" :min="3" placeholder="请输入备注" />
- </el-form-item>
- </el-col>
- </el-row>
- </el-form>
- </el-card>
- <!-- 其他信息 -->
- <el-card shadow="never">
- <template #header>
- <div class="flex justify-between items-center">
- <span>其他信息:</span>
- <el-button type="primary" plain @click="handleAddDetail">新增</el-button>
- </div>
- <div style="margin-left: 60px">
- <span>总计:{{ totalAmount.toFixed(2) }}</span>
- </div>
- </template>
- <el-table :data="detailList" border style="width: 100%">
- <el-table-column label="费用类型" min-width="150" align="center">
- <template #default="scope">
- <el-select v-model="scope.row.revenueId" placeholder="请选择" style="width: 100%">
- <el-option v-for="item in feeTypeList" :key="item.id" :label="`${item.revenueCode},${item.revenueName}`" :value="item.id" />
- </el-select>
- </template>
- </el-table-column>
- <el-table-column label="数量" min-width="120" align="center">
- <template #default="scope">
- <el-input-number
- v-model="scope.row.quantity"
- :precision="0"
- :controls="false"
- style="width: 100%"
- placeholder="请输入"
- @change="handleQuantityOrPriceChange(scope.$index)"
- />
- </template>
- </el-table-column>
- <el-table-column label="单价" min-width="120" align="center">
- <template #default="scope">
- <el-input-number
- v-model="scope.row.unitPrice"
- :precision="2"
- :controls="false"
- style="width: 100%"
- placeholder="请输入"
- @change="handleQuantityOrPriceChange(scope.$index)"
- />
- </template>
- </el-table-column>
- <el-table-column label="总金额" min-width="120" align="center">
- <template #default="scope">
- <el-input-number
- v-model="scope.row.totalAmount"
- :precision="2"
- :controls="false"
- style="width: 100%"
- placeholder="请输入"
- @change="calculateTotal"
- />
- </template>
- </el-table-column>
- <el-table-column label="备注" min-width="150" align="center">
- <template #default="scope">
- <el-input v-model="scope.row.remark" placeholder="请输入" />
- </template>
- </el-table-column>
- <el-table-column label="操作" width="80" fixed="right" align="center">
- <template #default="scope">
- <el-button link type="danger" @click="handleDeleteDetail(scope.$index)">删除</el-button>
- </template>
- </el-table-column>
- </el-table>
- </el-card>
- </div>
- </template>
- <script setup lang="ts">
- import { useRouter } from 'vue-router';
- import { listRevenueHeader, getRevenueHeader, addRevenueHeader, updateRevenueHeader } from '@/api/order/revenueHeader';
- import { RevenueHeaderVO, RevenueHeaderQuery, RevenueHeaderForm } from '@/api/order/revenueHeader/types';
- import { listCustomerInfo, getCustomerInfo } from '@/api/customer/customerFile/customerInfo';
- import { CustomerInfoVO } from '@/api/customer/customerFile/customerInfo/types';
- import { listRevenueExpense } from '@/api/company/revenueExpense';
- import { RevenueExpenseVO } from '@/api/company/revenueExpense/types';
- import { listComCurrency } from '@/api/company/comCurrency';
- import { ComCurrencyVO } from '@/api/company/comCurrency/types';
- import { getCompany } from '@/api/company/company';
- const { proxy } = getCurrentInstance() as ComponentInternalInstance;
- const { sys_platform_yes_no, check_status, revenue_type } = toRefs<any>(proxy?.useDict('sys_platform_yes_no', 'check_status', 'revenue_type'));
- const router = useRouter();
- const route = useRoute();
- const revenueHeaderFormRef = ref();
- const buttonLoading = ref(false);
- const customerList = ref<CustomerInfoVO[]>([]);
- const filteredCustomerList = ref<CustomerInfoVO[]>([]);
- const customerSearchLoading = ref(false);
- const feeTypeList = ref<RevenueExpenseVO[]>([]);
- const currencyList = ref<ComCurrencyVO[]>([]);
- // 防抖定时器
- let searchTimer: NodeJS.Timeout | null = null;
- const detailList = ref<any[]>([]);
- // 计算总金额
- const totalAmount = computed(() => {
- return detailList.value.reduce((sum, item) => {
- const amount = Number(item.totalAmount) || 0;
- return sum + amount;
- }, 0);
- });
- // 表单初始数据
- const initFormData: RevenueHeaderForm = {
- id: undefined,
- revenueType: '收入申请',
- orderRevenueCode: undefined,
- incomeOrderCode: undefined,
- otherRevenueType: undefined,
- customerId: undefined,
- customerCode: undefined,
- supplierId: undefined,
- isPrwTax: '0',
- currencyId: undefined,
- pushStatus: undefined,
- orderFile: undefined,
- status: undefined,
- remark: undefined,
- companyId: undefined,
- businessDept: undefined,
- customerService: undefined,
- businessStaff: undefined,
- createTime: new Date().toISOString().split('T')[0],
- orderRevenueDetails: []
- };
- const data = reactive<PageData<RevenueHeaderForm, RevenueHeaderQuery>>({
- form: { ...initFormData },
- queryParams: {
- pageNum: 1,
- pageSize: 10,
- revenueType: undefined,
- orderRevenueCode: undefined,
- incomeOrderCode: undefined,
- otherRevenueType: undefined,
- customerId: undefined,
- supplierId: undefined,
- isPrwTax: undefined,
- currencyId: undefined,
- pushStatus: undefined,
- orderFile: undefined,
- status: undefined,
- platformCode: undefined,
- params: {}
- },
- rules: {
- revenueType: [{ required: true, message: '收入单类型不能为空', trigger: 'change' }],
- customerCode: [{ required: true, message: '客户编号不能为空', trigger: 'blur' }],
- companyId: [{ required: true, message: '所属公司不能为空', trigger: 'change' }],
- currencyId: [{ required: true, message: '交易币别不能为空', trigger: 'change' }],
- isPrwTax: [{ required: true, message: '是否含税不能为空', trigger: 'change' }]
- }
- });
- const { queryParams, form, rules } = toRefs(data);
- // 防抖搜索客户
- const handleSearchCustomer = (query: string) => {
- if (searchTimer) {
- clearTimeout(searchTimer);
- }
- if (!query) {
- filteredCustomerList.value = [];
- return;
- }
- customerSearchLoading.value = true;
- searchTimer = setTimeout(async () => {
- try {
- const res = await listCustomerInfo({
- customerNo: query,
- pageNum: 1,
- pageSize: 10
- });
- filteredCustomerList.value = res.rows || [];
- } catch (error) {
- console.error('搜索客户失败:', error);
- filteredCustomerList.value = [];
- } finally {
- customerSearchLoading.value = false;
- }
- }, 500);
- };
- // 客户选择变化
- const handleCustomerChange = async (customerNo: string) => {
- if (!customerNo) {
- // 清空相关字段
- form.value.customerId = undefined;
- form.value.customerName = '';
- form.value.companyName = '';
- form.value.businessDept = '';
- form.value.customerService = '';
- form.value.businessStaff = '';
- return;
- }
- try {
- // 从筛选列表中找到选中的客户
- const selectedCustomer = filteredCustomerList.value.find((c) => c.customerNo === customerNo);
- if (!selectedCustomer) return;
- // 获取客户详细信息
- const res = await getCustomerInfo(selectedCustomer.id);
- const customerInfo = res.data;
- // 填充客户信息
- form.value.customerId = customerInfo.id;
- form.value.customerName = customerInfo.customerName;
- // 从客户销售信息中获取业务信息
- if (customerInfo.customerSalesInfoVo) {
- const salesInfo = customerInfo.customerSalesInfoVo as any;
- form.value.businessStaff = salesInfo.salesPerson || '';
- form.value.customerService = salesInfo.serviceStaff || '';
- form.value.businessDept = salesInfo.belongingDepartment || '';
- }
- // 获取所属公司信息
- if (customerInfo.belongCompanyId) {
- try {
- const companyRes = await getCompany(customerInfo.belongCompanyId);
- form.value.companyName = companyRes.data.companyName || '';
- form.value.companyId = customerInfo.belongCompanyId;
- } catch (error) {
- console.error('获取公司信息失败:', error);
- }
- }
- } catch (error) {
- console.error('获取客户信息失败:', error);
- ElMessage.error('获取客户信息失败');
- }
- };
- // 加载费用类型列表
- const loadFeeTypeList = async () => {
- try {
- // 根据revenueType决定查询条件
- const queryParams: any = {
- isShow: '0',
- pageNum: 1,
- pageSize: 1000
- };
- if (form.value.revenueType === '0') {
- // 收入申请:查询收入类
- queryParams.revenueFlag = '0';
- } else if (form.value.revenueType === '1') {
- // 费用申请:查询费用类
- queryParams.expenseFlag = '0';
- }
- const res = await listRevenueExpense(queryParams);
- feeTypeList.value = res.rows || [];
- } catch (error) {
- console.error('加载费用类型列表失败:', error);
- feeTypeList.value = [];
- }
- };
- // 加载币种列表
- const loadCurrencyList = async () => {
- try {
- const res = await listComCurrency({
- isShow: '0',
- pageNum: 1,
- pageSize: 1000
- });
- currencyList.value = res.rows || [];
- } catch (error) {
- console.error('加载币种列表失败:', error);
- currencyList.value = [];
- }
- };
- // 新增明细行
- const handleAddDetail = () => {
- detailList.value.push({
- revenueId: undefined,
- quantity: 0,
- unitPrice: 0,
- totalAmount: 0,
- remark: ''
- });
- };
- // 数量或单价变化时自动计算总金额
- const handleQuantityOrPriceChange = (index: number) => {
- const detail = detailList.value[index];
- if (detail) {
- const quantity = Number(detail.quantity) || 0;
- const unitPrice = Number(detail.unitPrice) || 0;
- detail.totalAmount = quantity * unitPrice;
- }
- };
- // 删除明细行
- const handleDeleteDetail = (index: number) => {
- detailList.value.splice(index, 1);
- };
- // 计算总金额(手动触发)
- const calculateTotal = () => {
- // 触发计算属性重新计算
- };
- // 提交表单
- const submitForm = async () => {
- try {
- await revenueHeaderFormRef.value?.validate();
- // 验证是否有明细数据
- if (!detailList.value || detailList.value.length === 0) {
- ElMessage.warning('请至少添加一条其他信息');
- return;
- }
- buttonLoading.value = true;
- // 组装明细数据到 orderRevenueDetails
- form.value.orderRevenueDetails = detailList.value.map((detail) => ({
- revenueId: detail.revenueId,
- quantity: detail.quantity,
- unitPrice: detail.unitPrice,
- totalAmount: detail.totalAmount,
- remark: detail.remark
- }));
- // 调用保存接口
- if (form.value.id) {
- await updateRevenueHeader(form.value);
- } else {
- await addRevenueHeader(form.value);
- }
- ElMessage.success('保存成功');
- // 跳转回列表页
- router.push('/order-center/order-revenue');
- } catch (error) {
- console.error('保存失败:', error);
- if (error !== false) {
- ElMessage.error('保存失败,请检查数据后重试');
- }
- } finally {
- buttonLoading.value = false;
- }
- };
- // 返回按钮
- const handleBack = () => {
- router.back();
- };
- // 取消
- const cancel = () => {
- router.back();
- };
- // 页面标题
- const pageTitle = computed(() => {
- const isEdit = !!route.query.id;
- if (isEdit) {
- return form.value.revenueType === '1' ? '编辑费用申请单' : '编辑收入申请单';
- }
- return form.value.revenueType === '1' ? '新增费用申请单' : '新增收入申请单';
- });
- // 加载订单详情
- const loadOrderDetail = async (id: string | number) => {
- try {
- const res = await getRevenueHeader(id);
- const data = res.data;
- // 填充表单数据
- Object.assign(form.value, data);
- // 填充明细列表
- if (data.orderRevenueDetailList && data.orderRevenueDetailList.length > 0) {
- detailList.value = data.orderRevenueDetailList.map((item: any) => ({
- revenueId: item.revenueId,
- quantity: item.quantity || 0,
- unitPrice: item.unitPrice || 0,
- totalAmount: item.totalAmount || 0,
- remark: item.remark || ''
- }));
- }
- } catch (error) {
- console.error('加载订单详情失败:', error);
- ElMessage.error('加载订单详情失败');
- }
- };
- // 组件挂载时加载数据
- onMounted(async () => {
- // 从路由参数获取revenueType和id
- const revenueType = route.query.revenueType as string;
- const orderId = route.query.id as string;
- if (revenueType) {
- form.value.revenueType = revenueType;
- } else {
- // 默认为收入申请
- form.value.revenueType = '0';
- }
- // 加载基础数据
- await loadFeeTypeList();
- await loadCurrencyList();
- // 如果有id,说明是编辑模式,加载订单详情
- if (orderId) {
- await loadOrderDetail(orderId);
- } else {
- // 新增模式,默认添加一个空行
- handleAddDetail();
- }
- });
- </script>
- <style scoped lang="scss">
- .mb-2 {
- margin-bottom: 16px;
- }
- .mt-4 {
- margin-top: 16px;
- }
- </style>
|