Merge remote-tracking branch 'origin/master'

This commit is contained in:
zjf committed 2025-07-04 17:11:08 +08:00
commit d4f0205c4d
9 files changed
+597 -552

No files matched your search

+14
View File
@@ -8,6 +8,20 @@ export function invoiceBack(query: any) {
})
}
/**
* 发票申请
* @param id 发票id
* @param picUrl 发票图片
* @returns
*/
export function apply(data: any) {
return request({
url: "/wallet/walletRechargeInvoice/apply",
method: "post",
data: data,
})
}
/**
* 根据申请id获取发票详情
* @param id 申请id
@@ -1,21 +1,19 @@
<template>
<div class="w-full h-full p-1">
<el-row class="my-1">
<el-button type="primary" @click="pushEvent">新增</el-button>
<el-button @click="removeSelectRowEvent">删除选中</el-button>
</el-row>
<el-row class="mb-2">
<el-button type="primary" @click="pushEvent">新增</el-button>
</el-row>
<vxe-table
ref="editableTableRef"
border
show-overflow
max-height="380"
:edit-rules="validRules"
:column-config="{ resizable: true }"
:row-config="{ isHover: true }"
:resizable-config="{ dragMode: 'fixed' }"
:data="auxiliaryCodeList"
:edit-config="{
<vxe-table
ref="tableRef"
show-overflow
max-height="340"
height="340"
:edit-rules="validRules"
:column-config="{ resizable: true }"
:row-config="{ isHover: true }"
:resizable-config="{ dragMode: 'fixed' }"
:data="auxiliaryCodeList"
:edit-config="{
trigger: 'click',
mode: 'cell',
beforeEditMethod({ row, column }:any) {
@@ -26,136 +24,121 @@
return true
},
}"
size="mini"
align="center"
>
<vxe-column type="checkbox" width="40" fixed="left" />
<vxe-column type="seq" width="50" fixed="left" />
<vxe-column field="unit" title="单位" :edit-render="{}">
<template #edit="{ row, $rowIndex }">
<el-select v-model="row.unitId" @change="handleUnitIdChange(row.unitId, $rowIndex)">
<template v-for="item in computedSmErpUnitEntityList">
<el-option :label="item.unit" :value="item.id" />
</template>
</el-select>
</template>
<template #default="{ row }">
<span v-if="row.unitId">{{ computedSmErpUnitEntityList?.find((item: rowVU) => item.id === row.unitId)?.unit }}</span>
<span v-else style="color: #c0c4cf">请选择</span>
</template>
</vxe-column>
<vxe-column field="taste" title="口味">
<template #default="{ row }">
{{ computedSmErpUnitEntityList?.find((item: rowVU) => item.id === row.unitId)?.taste }}
</template>
</vxe-column>
<vxe-column field="barCode" title="辅助条码" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input v-model.trim="row.barCode" />
</template>
</vxe-column>
</vxe-table>
</div>
size="mini"
align="center"
>
<vxe-column type="seq" width="50" fixed="left" />
<!-- <vxe-column type="checkbox" width="40" fixed="left" /> -->
<vxe-column field="unit" title="单位" :edit-render="{}">
<template #edit="{ row, $rowIndex }">
<el-select v-model="row.unitId" @change="handleUnitIdChange(row.unitId, $rowIndex)">
<template v-for="item in unitSelectOptions">
<el-option :label="item.unit" :value="item.id">
<span class="float-left">单位:{{ item.unit }}</span>
<span class="float-right ml-4">口味:{{ item.taste }}</span>
</el-option>
</template>
</el-select>
</template>
<template #default="{ row }">
<span v-if="row.unitId">{{ unitSelectOptions?.find((item: rowVU) => item.id === row.unitId)?.unit }}</span>
<span v-else style="color: #c0c4cf">请选择</span>
</template>
</vxe-column>
<vxe-column field="taste" title="口味">
<template #default="{ row }">
{{ unitSelectOptions?.find((item: rowVU) => item.id === row.unitId)?.taste }}
</template>
</vxe-column>
<vxe-column field="barCode" title="辅助条码" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input v-model.trim="row.barCode" />
</template>
</vxe-column>
<vxe-column title="操作">
<template #default="scope">
<el-popconfirm title="是否删除?" @confirm="removeRow(scope.$rowIndex)">
<template #reference><el-button size="small">删除</el-button></template>
</el-popconfirm>
</template>
</vxe-column>
</vxe-table>
</template>
<script setup lang="ts">
import { nanoid } from "nanoid"
import { useMessage } from "/@/hooks/message"
import { type rowVU } from "./package-unit.vue"
import { useMessage } from "/@/hooks/message"
export interface rowVC {
id: string
unitId: string
unit: string
barCode: string
taste: string
isNew?: boolean
barCode: string
}
const auxiliaryCodeList = defineModel("modelValue", {
default: [
{
id: nanoid(5),
unitId: "",
unit: "",
taste: "",
barCode: "",
},
],
})
const props = withDefaults(defineProps<{ smErpUnitEntityList?: rowVU[] }>(), { smErpUnitEntityList: [] as any })
const auxiliaryCodeList = defineModel<any>("modelValue", { default: [] })
const props = withDefaults(
defineProps<{
smErpUnitEntityList?: rowVU[]
}>(),
{
smErpUnitEntityList: [] as any,
},
)
const editableTableRef = ref()
const tableRef = ref()
const validRules = {
// unit: [{ required: true, message: "包装单位不能为空", trigger: "blur" }],
// barCode: [{ required: true, message: "条码不能为空", trigger: "blur" }],
}
// 底部表格行新增
// 底部新增行
const pushEvent = () => {
if (props.smErpUnitEntityList?.length === 0) return useMessage().warning("请先添加包装单位")
const newRow: rowVC = {
id: nanoid(5),
id: "tmp_" + nanoid(5),
unitId: "",
unit: "",
barCode: "",
taste: "",
isNew: true,
barCode: "",
}
auxiliaryCodeList.value.push(newRow)
nextTick(() => {
const $table = editableTableRef.value
const $table = tableRef.value
if ($table) {
$table.setEditRow(newRow)
}
})
}
// 删除行
const removeRow = (rowIndex: number) => {
auxiliaryCodeList.value.splice(rowIndex, 1)
}
// 可选择的包装单位下拉菜单
const unitSelectOptions = computed(() => props.smErpUnitEntityList?.filter((item: rowVU) => item.unit))
// 包装单位行删除时清除辅助条码中选择该包装单位的行
watch(
() => props.smErpUnitEntityList?.length,
() => {
auxiliaryCodeList.value = auxiliaryCodeList.value.filter((codeItem: rowVC) =>
props.smErpUnitEntityList?.some((item: rowVU) => codeItem.unitId === item.id),
)
(newValue, oldValue) => {
if (newValue! < oldValue!) {
auxiliaryCodeList.value = auxiliaryCodeList.value.filter((codeItem: rowVC) =>
props.smErpUnitEntityList?.some((item: rowVU) => codeItem.unitId === item.id),
)
}
},
)
// 计算辅助条码中可选择的包装单位下拉菜单
const computedSmErpUnitEntityList = computed(() => props.smErpUnitEntityList?.filter((item: rowVU) => item.unit))
// 包装单位下拉选择变化
const handleUnitIdChange = (unitId: string, rowIndex: number) => {
const unitItem = computedSmErpUnitEntityList.value?.find((item: rowVU) => item.id == unitId)
const unitItem = unitSelectOptions.value?.find((item: rowVU) => item.id == unitId)
;(auxiliaryCodeList.value[rowIndex] as any).unit = unitItem?.unit
;(auxiliaryCodeList.value[rowIndex] as any).taste = unitItem?.taste
}
// 删除选中的行
const removeSelectRowEvent = () => {
const $table = editableTableRef.value
if ($table) {
const selectRecords = $table.getCheckboxRecords()
if (selectRecords.length > 0) {
auxiliaryCodeList.value = auxiliaryCodeList.value.filter((item: rowVC) => !selectRecords.some((row: rowVC) => row.id === item.id))
}
}
}
// 校验可编辑表格 成功返回 true 失败返回 false
// const editableTableValidate = async () => {
// const tableValidate = async () => {
// // 全量校验
// const $table = editableTableRef.value
// const $table = tableRef.value
// if ($table) {
// const errMap = await $table.validate(true)
// if (errMap) {
@@ -169,6 +152,6 @@ const removeSelectRowEvent = () => {
// }
// defineExpose({
// editableTableValidate,
// tableValidate,
// })
</script>
@@ -1,84 +1,112 @@
<template>
<el-row>
<el-col :span="12" class="mb20">
<el-col :span="8" class="mb20">
<el-form-item label="货号" prop="productCode">
<el-input v-model.trim="form.productCode" placeholder="请输入货号" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-col :span="8" class="mb20">
<el-form-item label="商品名称" prop="productName">
<el-input v-model.trim="form.productName" placeholder="请输入商品名称" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="货商" prop="supplierId">
<SelectSupermarketSupplier v-model="form.supplierId" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="商品分类" prop="categoryId">
<el-select v-model="form.categoryId" placeholder="请选择商品分类">
<el-option v-for="item in categoryOptions" :key="item?.id" :label="item?.name" :value="item?.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="品牌" prop="brandId">
<el-select v-model="form.brandId" placeholder="请选择品牌">
<el-option v-for="item in brandOptions" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="商品性质" prop="productNature">
<el-select v-model="form.productNature" placeholder="请选择商品性质">
<el-option :value="item.value" :label="item.label" v-for="(item, index) in supermarket_nature" :key="index" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="24" class="mb20">
<el-form-item label="商品封面图" prop="picUrl">
<upload-img v-model:imageUrl="form.picUrl" />
</el-form-item>
</el-col>
<el-col :span="24" class="mb20">
<el-col :span="8" class="mb20">
<el-form-item label="商品状态" prop="status">
<el-radio-group v-model="form.status">
<el-radio :label="item.value" v-for="(item, index) in status" border :key="index">{{ item.label }}</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-col :span="8" class="mb20">
<el-form-item label="货商" prop="supplierId">
<SelectSupermarketSupplier v-model="form.supplierId" />
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="商品分类" prop="categoryId">
<el-select v-model="form.categoryId" placeholder="请选择商品分类">
<el-option v-for="item in categoryOptions" :key="item?.id" :label="item?.name" :value="item?.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="商品性质" prop="productNature">
<el-select v-model="form.productNature" placeholder="请选择商品性质">
<el-option :value="item.value" :label="item.label" v-for="(item, index) in supermarket_nature" :key="index" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="品牌" prop="brandId">
<el-select v-model="form.brandId" placeholder="请选择品牌">
<el-option v-for="item in brandOptions" :key="item.id" :label="item.name" :value="item.id" />
</el-select>
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="排序字段" prop="sort">
<el-input-number :min="0" :max="1000" :precision="0" v-model="form.sort" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-col :span="8" class="mb20">
<el-form-item label="毛利率" prop="grossMargin">
<el-input-number v-model="form.grossMargin" :min="0" :precision="2" />
</el-form-item>
</el-col>
<el-col :span="24" class="mb20">
<el-form-item label="产地" prop="origin">
<el-input v-model.trim="form.origin" placeholder="请输入产地" />
<el-col :span="8" class="mb20">
<el-form-item label="商品封面图" prop="picUrl">
<upload-img v-model:imageUrl="form.picUrl" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-col :span="16" class="mb20">
<el-form-item label="商品产地" prop="origin">
<el-input v-model.trim="form.origin" placeholder="请输入商品产地" />
</el-form-item>
</el-col>
<el-col :span="24" class="mb20">
<hr />
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="条码" prop="barCode">
<el-input v-model.trim="form.barCode" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-col :span="8" class="mb20">
<el-form-item label="规格" prop="spec">
<el-input v-model.trim="form.spec" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-col :span="8" class="mb20">
<el-form-item label="单位" prop="unit">
<el-input v-model.trim="form.unit" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-col :span="8" class="mb20">
<el-form-item label="内装数" prop="packageNum">
<el-input-number v-model="form.packageNum" :min="0" :precision="0" />
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="进价(元)" prop="purchasePrice">
<el-input-number v-model="form.purchasePrice" :min="0" :precision="2" />
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="零售价(元)" prop="retailPrice">
<el-input-number v-model="form.retailPrice" :min="0" :precision="2" />
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="促销价(元)" prop="promotionPrice">
<el-input-number v-model="form.promotionPrice" :min="0" :precision="2" />
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="成本价(元)" prop="costPrice">
<el-input-number v-model="form.costPrice" :min="0" :precision="2" />
</el-form-item>
</el-col>
<el-col :span="8" class="mb20">
<el-form-item label="单位状态" prop="unitStatus">
<el-radio-group v-model="form.unitStatus">
<el-radio label="0" border>正常</el-radio>
@@ -86,31 +114,6 @@
</el-radio-group>
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="内装数" prop="packageNum">
<el-input-number v-model="form.packageNum" :min="0" :precision="0" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="进价(元)" prop="purchasePrice">
<el-input-number v-model="form.purchasePrice" :min="0" :precision="2" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="零售价(元)" prop="retailPrice">
<el-input-number v-model="form.retailPrice" :min="0" :precision="2" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="促销价(元)" prop="promotionPrice">
<el-input-number v-model="form.promotionPrice" :min="0" :precision="2" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-form-item label="成本价(元)" prop="costPrice">
<el-input-number v-model="form.costPrice" :min="0" :precision="2" />
</el-form-item>
</el-col>
</el-row>
</template>
@@ -1,33 +1,31 @@
<template>
<div class="w-full h-full p-1">
<el-row class="my-1">
<el-button type="primary" @click="pushEvent()">新增</el-button>
<el-button @click="removeSelectRowEvent">删除选中</el-button>
<el-tooltip effect="light" placement="right">
<template #content>
<el-alert class="w-[500px] h-24" type="warning" show-icon :closable="false">
<p>
注:内装数据必须为该商品的最小售卖的基本单位,否则无法完成库存数量转换,影响erp库存自动扣减操作。
例如:一瓶矿泉水内装填'1',为售卖的最小基础单位,如果想按箱卖,在继续添加包装单位为箱,内装为24
</p>
</el-alert>
</template>
<el-icon class="text-xl my-auto ml-4 text-yellow-600"><WarningFilled /></el-icon>
</el-tooltip>
</el-row>
<el-row class="mb-2">
<el-button type="primary" @click="pushEvent()">新增</el-button>
<el-tooltip effect="light" placement="right">
<template #content>
<el-alert class="w-[500px] h-24" type="warning" show-icon :closable="false">
<p>
注:内装数据必须为该商品的最小售卖的基本单位,否则无法完成库存数量转换,影响erp库存自动扣减操作。
例如:一瓶矿泉水内装填'1',为售卖的最小基础单位,如果想按箱卖,在继续添加包装单位为箱,内装为24
</p>
</el-alert>
</template>
<el-icon class="text-xl my-auto ml-4 text-yellow-600"><WarningFilled /></el-icon>
</el-tooltip>
</el-row>
<vxe-table
ref="editableTableRef"
border
show-overflow
max-height="380"
:radio-config="{ highlight: true }"
:column-config="{ resizable: true }"
:row-config="{ isHover: true }"
:resizable-config="{ dragMode: 'fixed' }"
:data="packageUnitList"
:edit-rules="validRules"
:edit-config="{
<vxe-table
ref="tableRef"
show-overflow
max-height="340"
height="340"
:edit-rules="validRules"
:radio-config="{ highlight: true }"
:column-config="{ resizable: true }"
:row-config="{ isHover: true }"
:resizable-config="{ dragMode: 'fixed' }"
:data="packageUnitList"
:edit-config="{
trigger: 'click',
mode: 'cell',
beforeEditMethod({ row, column }:any) {
@@ -38,133 +36,156 @@
return true
},
}"
size="mini"
align="center"
>
<vxe-column type="seq" width="50" fixed="left" />
<vxe-column type="checkbox" width="40" fixed="left" />
<vxe-column type="radio" title="基础单位" fixed="left" />
<vxe-column field="barCode" title="条码" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input v-model.trim="row.barCode" />
</template>
</vxe-column>
<vxe-column field="spec" title="规格" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input v-model.trim="row.spec" />
</template>
</vxe-column>
<vxe-column field="unit" title="单位名称" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input v-model.trim="row.unit" @input="(value: string | number) => handleUnitInput(row, value)" />
</template>
</vxe-column>
<vxe-column field="taste" title="口味" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input v-model.trim="row.taste" @input="(value: string | number) => handleTasteInput(row, value)" />
</template>
</vxe-column>
<vxe-column field="status" title="状态" :edit-render="{}">
<template #edit="{ row }">
<el-select v-model="row.status">
<el-option label="正常" value="0" />
<el-option label="停销" value="1" />
</el-select>
</template>
<template #default="{ row }">
<span v-if="row.status == '0'">正常</span>
<span v-else-if="row.status == '1'">停销</span>
<span v-else style="color: #c0c4cf">请选择</span>
</template>
</vxe-column>
<vxe-column field="packageNum" title="内装数" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input-number v-model="row.packageNum" controls-position="right" :min="1" :precision="0" />
</template>
</vxe-column>
<vxe-column field="purchasePrice" title="进价(元)" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input-number v-model="row.purchasePrice" controls-position="right" :min="0" :precision="2" />
</template>
</vxe-column>
<vxe-column field="retailPrice" title="零售价(元)" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input-number v-model="row.retailPrice" controls-position="right" :min="0.01" :precision="2" />
</template>
</vxe-column>
<vxe-column field="promotionPrice" title="促销价(元)" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input-number v-model="row.promotionPrice" controls-position="right" :min="0" :precision="2" />
</template>
</vxe-column>
<vxe-column field="costPrice" title="成本价(元)" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input-number v-model="row.costPrice" controls-position="right" :min="0" :precision="2" />
</template>
</vxe-column>
</vxe-table>
</div>
size="mini"
align="center"
>
<vxe-column type="seq" width="50" fixed="left" />
<!-- <vxe-column type="checkbox" width="40" fixed="left" /> -->
<vxe-column type="radio" title="基础单位" fixed="left" />
<vxe-column field="barCode" title="条码" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input v-model.trim="row.barCode" />
</template>
</vxe-column>
<vxe-column field="spec" title="规格" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input v-model.trim="row.spec" />
</template>
</vxe-column>
<vxe-column field="unit" title="单位名称" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="slotParams">
<el-input v-model.trim="slotParams.row.unit" @input="slotInputChange(slotParams)" />
</template>
</vxe-column>
<vxe-column field="taste" title="口味" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="slotParams">
<el-input v-model.trim="slotParams.row.taste" @input="slotInputChange(slotParams)" />
</template>
</vxe-column>
<vxe-column field="status" title="状态" :edit-render="{}">
<template #edit="{ row }">
<el-select v-model="row.status">
<el-option label="正常" value="0" />
<el-option label="停销" value="1" />
</el-select>
</template>
<template #default="{ row }">
<span v-if="row.status == '0'">正常</span>
<span v-else-if="row.status == '1'">停销</span>
<span v-else style="color: #c0c4cf">请选择</span>
</template>
</vxe-column>
<vxe-column field="packageNum" title="内装数" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input-number v-model="row.packageNum" controls-position="right" :min="1" :precision="0" />
</template>
</vxe-column>
<vxe-column field="purchasePrice" title="进价(元)" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input-number v-model="row.purchasePrice" controls-position="right" :min="0" :precision="2" />
</template>
</vxe-column>
<vxe-column field="retailPrice" title="零售价(元)" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input-number v-model="row.retailPrice" controls-position="right" :min="0.01" :precision="2" />
</template>
</vxe-column>
<vxe-column field="promotionPrice" title="促销价(元)" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input-number v-model="row.promotionPrice" controls-position="right" :min="0" :precision="2" />
</template>
</vxe-column>
<vxe-column field="costPrice" title="成本价(元)" :edit-render="{ autoFocus: 'input', placeholder: '请输入' }">
<template #edit="{ row }">
<el-input-number v-model="row.costPrice" controls-position="right" :min="0" :precision="2" />
</template>
</vxe-column>
<vxe-column title="操作">
<template #default="scope">
<el-popconfirm title="是否删除?" @confirm="removeRow(scope.$rowIndex)">
<template #reference><el-button size="small">删除</el-button></template>
</el-popconfirm>
</template>
</vxe-column>
</vxe-table>
</template>
<script setup lang="ts">
import { VxeTablePropTypes } from "vxe-table"
import { nanoid } from "nanoid"
import { useMessage } from "/@/hooks/message"
export interface rowVU {
id: string
barCode: string
spec: string
unit: string
unitId?: string
status: string
packageNum: number
purchasePrice: number
retailPrice: number
promotionPrice: number
costPrice: number
isNew?: boolean
isBase?: boolean | null
flag?: string
taste?: string
}
const packageUnitList = defineModel<rowVU[]>("modelValue", {
default: [
const packageUnitList = defineModel<rowVU[]>("modelValue", { default: [] })
const tableRef = ref()
const validRules = ref<VxeTablePropTypes.EditRules<rowVU>>({
barCode: [{ required: true, message: "不能为空" }],
unit: [
{ required: true, message: "不能为空" },
{
id: nanoid(5),
barCode: "",
spec: "",
unit: "",
status: "0",
packageNum: 1,
purchasePrice: 0,
retailPrice: 0.01,
promotionPrice: 0,
costPrice: 0,
taste: "",
validator({ cellValue, row, rowIndex }) {
if (
cellValue &&
packageUnitList.value
.filter((item: rowVU, index: number) => rowIndex != index && item.taste == row.taste)
.some((v: rowVU) => v.unit == row.unit)
)
return new Error("该包装单位的口味已存在")
},
},
],
status: [{ required: true, message: "不能为空" }],
packageNum: [{ required: true, message: "不能为空" }],
retailPrice: [{ required: true, type: "number", min: 0.01, message: "不能为0" }],
purchasePrice: [{ required: true, message: "不能为空" }],
taste: [
{
validator({ cellValue, row, rowIndex }) {
if (
cellValue &&
packageUnitList.value
.filter((item: rowVU, index: number) => rowIndex != index && item.taste == row.taste)
.some((v: rowVU) => v.unit == row.unit)
)
return new Error("该包装单位的口味已存在")
},
},
],
})
const editableTableRef = ref()
const validRules = {
barCode: [{ required: true, message: "条码不能为空", trigger: "blur" }],
// spec: [{ required: true, message: "规格不能为空", trigger: "blur" }],
unit: [{ required: true, message: "单位不能为空", trigger: "blur" }],
status: [{ required: true, message: "状态不能为空", trigger: "blur" }],
packageNum: [{ required: true, message: "内装数不能为空", trigger: "blur" }],
retailPrice: [{ required: true, type: "number", min: 0.01, message: "零售价不能为0" }],
purchasePrice: [{ required: true, message: "进价不能为空", trigger: "blur" }],
// promotionPrice: [{ required: true, message: "促销价不能为空", trigger: "blur" }],
// 自定义编辑模板的input校验
const slotInputChange = (slotParams: any) => {
const $table = tableRef.value
if ($table) {
$table.updateStatus(slotParams)
}
}
// 底部表格行新增
// 底部新增行
const pushEvent = (row?: rowVU | undefined) => {
const newRow = {} as rowVU
if (row) {
Object.assign(newRow, row)
} else {
row = {
id: nanoid(5),
id: "tmp_" + nanoid(5),
barCode: "",
spec: "",
unit: "",
@@ -175,51 +196,44 @@ const pushEvent = (row?: rowVU | undefined) => {
promotionPrice: 0,
costPrice: 0,
taste: "",
isNew: true,
}
Object.assign(newRow, row)
}
packageUnitList.value.push(newRow)
nextTick(() => {
const $table = editableTableRef.value
const $table = tableRef.value
if ($table) {
$table.setEditRow(newRow)
}
})
}
// 删除选中的行
const removeSelectRowEvent = () => {
const $table = editableTableRef.value
// 删除行
const removeRow = (rowIndex: number) => {
packageUnitList.value.splice(rowIndex, 1)
}
// 设置单选的行
const setRadioRow = (index: number) => {
const $table = tableRef.value
if ($table) {
const selectRecords = $table.getCheckboxRecords()
if (selectRecords.length > 0) {
packageUnitList.value = packageUnitList.value.filter((item: rowVU) => !selectRecords.some((row: rowVU) => row.id === item.id))
}
$table.setRadioRow(packageUnitList.value[index])
}
}
// 获取单选的行
const getRadioRow = () => {
const $table = editableTableRef.value
const $table = tableRef.value
if ($table) {
const currRadioRow = $table.getRadioRecord()
return currRadioRow
}
}
// 设置单选的行
const setRadioRow = (index: number) => {
const $table = editableTableRef.value
if ($table) {
$table.setRadioRow(packageUnitList.value[index])
}
}
// 校验可编辑表格 成功返回 true 失败返回 false
const editableTableValidate = async () => {
// 校验表格 成功返回 true 失败返回 false
const tableValidate = async () => {
// 全量校验
const $table = editableTableRef.value
const $table = tableRef.value
if ($table) {
const errMap = await $table.validate(true)
if (errMap) {
@@ -232,32 +246,10 @@ const editableTableValidate = async () => {
}
}
// 口味字段值改变
const handleTasteInput = (row: rowVU, value: string | number) => {
if (
packageUnitList.value.filter((item: rowVU) => item.id != row.id && item.unit == row.unit).some((item: rowVU) => item.taste == value)
) {
useMessage().warning("该包装单位的口味已存在")
return false
}
return true
}
// 单位字段值改变
const handleUnitInput = (row: rowVU, value: string | number) => {
if (
packageUnitList.value.filter((item: rowVU) => item.id != row.id && item.unit == row.unit).some((item: rowVU) => item.taste == row.taste)
) {
useMessage().warning("该包装单位的口味已存在")
return false
}
return true
}
defineExpose({
editableTableValidate,
getRadioRow,
tableValidate,
setRadioRow,
getRadioRow,
pushEvent,
})
</script>
@@ -1,18 +1,18 @@
<template>
<el-row>
<el-col :span="24" class="mb20">
<el-col :span="8" class="mb20">
<el-form-item label="期初库存" prop="stock" class="flex w-full h-full">
<el-input-number v-model="stock" :min="0" :precision="0" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-col :span="8" class="mb20">
<el-form-item label="库存上限" prop="inventoryUpperLimit">
<el-input-number v-model="inventoryUpperLimit" :min="0" :precision="0" />
</el-form-item>
</el-col>
<el-col :span="12" class="mb20">
<el-col :span="8" class="mb20">
<el-form-item label="库存下限" prop="inventoryLowerLimit">
<el-input-number v-model="inventoryLowerLimit" :min="0" :precision="0" />
</el-form-item>
@@ -137,6 +137,7 @@ const handleFileSuccess = (response: any) => {
* 提交表单,触发上传
*/
const submitFileForm = () => {
state.upload.isUploading = true
uploadRef.value.submit()
}
@@ -1,6 +1,6 @@
<template>
<el-dialog width="80%" :title="form.id ? '编辑' : '新增'" v-model="visible" :close-on-click-modal="false" draggable>
<el-form ref="formRef" :model="form" :rules="dataRules" label-width="150px" v-loading="loading">
<el-dialog width="90%" :title="form.id ? '编辑' : '新增'" v-model="visible" :close-on-click-modal="false" draggable>
<el-form ref="formRef" :model="form" :rules="dataRules" label-width="100px" v-loading="loading">
<el-tabs class="el-tabs" v-model="tabPaneActiveName" @tab-change="handleTabChange" type="border-card">
<el-tab-pane class="el-tab-pane" label="基础信息" name="基础信息">
<base-info v-model="form" />
@@ -16,15 +16,15 @@
/>
</el-tab-pane>
<el-tab-pane class="el-tab-pane" label="辅助条码" name="辅助条码">
<auxiliary-code :smErpUnitEntityList="form.smErpUnitEntityList" v-model="form.smErpAuxiliaryCodeEntityList" />
<auxiliary-code v-model="form.smErpAuxiliaryCodeEntityList" :smErpUnitEntityList="form.smErpUnitEntityList" />
</el-tab-pane>
</el-tabs>
</el-form>
<template #footer>
<el-button v-if="currentTabPaneIndex != 0" type="primary" @click="currentTabPaneIndex--" :disabled="loading">上一步</el-button>
<el-button v-if="currentTabPaneIndex != tabPaneEnum.length - 1" type="primary" @click="nextStep">下一步</el-button>
<el-button v-if="currentTabPaneIndex == tabPaneEnum.length - 1" type="primary" @click="onSubmit" :loading="loading">提 交</el-button>
<el-button v-if="tabPaneActiveIndex != 0" type="primary" @click="previousStep" :disabled="loading">上一步</el-button>
<el-button v-if="tabPaneActiveIndex != tabPaneName.length - 1" type="primary" @click="nextStep">下一步</el-button>
<el-button v-if="tabPaneActiveIndex == tabPaneName.length - 1" type="primary" @click="onSubmit" :loading="loading">提 交</el-button>
<el-button @click="visible = false">取消</el-button>
</template>
</el-dialog>
@@ -43,15 +43,14 @@ import { nanoid } from "nanoid"
const emit = defineEmits(["refresh"])
const formRef = ref()
const packageUnitRef = ref()
const visible = ref(false)
const loading = ref(false)
const tabPaneEnum = ["基础信息", "包装单位", "库存", "辅助条码"]
const currentTabPaneIndex = ref(0)
const tabPaneActiveName = computed(() => tabPaneEnum[currentTabPaneIndex.value])
const formRef = ref()
const packageUnitRef = ref()
const tabPaneName = ["基础信息", "包装单位", "库存", "辅助条码"]
const tabPaneActiveName = ref(tabPaneName[0])
const tabPaneActiveIndex = ref(0)
// 提交表单数据
const form = reactive<any>({
id: "",
merchantId: "",
@@ -83,9 +82,8 @@ const form = reactive<any>({
promotionPrice: 0,
costPrice: 0,
})
// 基本信息的金额转为单位分
const formatedBaseFormMoney = computed(() => {
const formatedStorePrice = computed(() => {
return {
grossMargin: storePrice(form.grossMargin),
purchasePrice: storePrice(form.purchasePrice),
@@ -95,7 +93,7 @@ const formatedBaseFormMoney = computed(() => {
}
})
// 定义校验规则
// 表单校验规则
const dataRules = {
productNature: [{ required: true, message: "请选择商品性质", trigger: "blur" }],
merchantId: [{ required: true, message: "商户不能为空", trigger: "blur" }],
@@ -122,11 +120,56 @@ const dataRules = {
// costPrice: [{ required: true, message: "成本价不能为空", trigger: "blur" }],
}
// tab栏切换
const handleTabChange = (name: TabPaneName) => {
tabPaneActiveIndex.value = tabPaneName.findIndex((item) => item === name)
setDefaultPackageUnit()
}
// 上一步
const previousStep = () => {
tabPaneActiveIndex.value--
tabPaneActiveName.value = tabPaneName[tabPaneActiveIndex.value]
setDefaultPackageUnit()
}
// 下一步
const nextStep = () => {
tabPaneActiveIndex.value++
tabPaneActiveName.value = tabPaneName[tabPaneActiveIndex.value]
setDefaultPackageUnit()
}
// 默认设置一行基础包装单位
const setDefaultPackageUnit = () => {
if (!form.id && tabPaneActiveIndex.value == 1) {
const isFlagRowExist = form.smErpUnitEntityList.some((item: rowVU) => item.flag === "defaultPackageUnitRow")
if (isFlagRowExist) return
const row = {
id: "tmp_" + nanoid(5),
barCode: form.barCode,
spec: form.spec,
unit: form.unit,
status: form.unitStatus,
packageNum: form.packageNum,
purchasePrice: form.purchasePrice,
retailPrice: form.retailPrice,
promotionPrice: form.promotionPrice,
costPrice: form.costPrice,
flag: "defaultPackageUnitRow",
}
packageUnitRef.value.pushEvent(row)
packageUnitRef.value.setRadioRow(0) // 自动设置基础包装单位的radio单选行
}
}
// 打开弹窗
const openDialog = async (id: string) => {
visible.value = true
currentTabPaneIndex.value = 0
tabPaneActiveIndex.value = 0
tabPaneActiveName.value = tabPaneName[tabPaneActiveIndex.value]
form.id = ""
visible.value = true
// 重置表单数据
resetForm()
@@ -144,10 +187,10 @@ const openDialog = async (id: string) => {
const getsupermarketSpuData = async (id: string) => {
loading.value = true
try {
const res = await getObj(id)
if (res.code === 0) {
res.data.smErpUnitEntityList = res.data.smErpUnitEntityList.map((item: rowVU) => {
// 格式化金额数据
const { code, data } = await getObj(id)
if (code === 0) {
data.smErpUnitEntityList = data.smErpUnitEntityList.map((item: rowVU) => {
// 格式化金额
item.retailPrice = parseFloat(displayPrice(item.retailPrice, ""))
item.promotionPrice = parseFloat(displayPrice(item.promotionPrice, ""))
item.purchasePrice = parseFloat(displayPrice(item.purchasePrice, ""))
@@ -156,12 +199,12 @@ const getsupermarketSpuData = async (id: string) => {
})
Object.assign(form, {
...res.data,
grossMargin: parseFloat(displayPrice(res.data.grossMargin, "")),
retailPrice: parseFloat(displayPrice(res.data.retailPrice, "")),
promotionPrice: parseFloat(displayPrice(res.data.promotionPrice, "")),
purchasePrice: parseFloat(displayPrice(res.data.purchasePrice, "")),
costPrice: parseFloat(displayPrice(res.data.costPrice, "")),
...data,
grossMargin: parseFloat(displayPrice(data.grossMargin, "")),
retailPrice: parseFloat(displayPrice(data.retailPrice, "")),
promotionPrice: parseFloat(displayPrice(data.promotionPrice, "")),
purchasePrice: parseFloat(displayPrice(data.purchasePrice, "")),
costPrice: parseFloat(displayPrice(data.costPrice, "")),
})
}
} catch (error: any) {
@@ -178,44 +221,6 @@ const resetForm = () => {
form.smErpAuxiliaryCodeEntityList = []
}
// tab栏切换
const handleTabChange = (name: TabPaneName) => {
currentTabPaneIndex.value = tabPaneEnum.findIndex((item) => item === name)
if (form.id) return
setDefaultPackageUnit()
}
// 下一步
const nextStep = () => {
currentTabPaneIndex.value++
if (form.id) return
setDefaultPackageUnit()
}
// 默认设置一行基础包装单位
const setDefaultPackageUnit = () => {
if (currentTabPaneIndex.value == 1) {
const isFlagRowExist = form.smErpUnitEntityList.some((item: rowVU) => item.flag === "defaultAddedPackageUnit")
if (isFlagRowExist) return
const row = {
id: nanoid(5),
barCode: form.barCode,
spec: form.spec,
unit: form.unit,
status: form.unitStatus,
packageNum: form.packageNum,
purchasePrice: form.purchasePrice,
retailPrice: form.retailPrice,
promotionPrice: form.promotionPrice,
costPrice: form.costPrice,
isNew: true,
flag: "defaultAddedPackageUnit",
}
packageUnitRef.value.pushEvent(row)
packageUnitRef.value.setRadioRow(0) // 自动设置基础包装单位的radio单选行
}
}
// 整理包装单位列表
const settlePackageUnitList = () => {
const curRadioRowUnit = packageUnitRef.value.getRadioRow()
@@ -227,15 +232,12 @@ const settlePackageUnitList = () => {
} else {
item.isBase = false
}
if (item.id.startsWith("tmp_")) item.id = ""
// 转换金额单位
item.costPrice = storePrice(item.costPrice)
item.promotionPrice = storePrice(item.promotionPrice)
item.purchasePrice = storePrice(item.purchasePrice)
item.retailPrice = storePrice(item.retailPrice)
if (item.isNew) {
item.id = ""
delete item.isNew
}
return item
})
}
@@ -246,13 +248,8 @@ const settleAuxiliaryCode = () => {
return smErpAuxiliaryCodeEntityList
.filter((item: rowVC) => item.unitId)
.map((item: rowVC) => {
const curPackageUnitItem = form.smErpUnitEntityList.find((unitItem: any) => unitItem.id == item.unitId)
if (item.isNew) {
item.id = ""
if (curPackageUnitItem?.isNew) item.unitId = ""
delete item.isNew
}
if (item.id.startsWith("tmp_")) item.id = ""
if (item.unitId.startsWith("tmp_")) item.unitId = ""
return item
})
}
@@ -262,27 +259,21 @@ const onSubmit = async () => {
const valid = await formRef.value.validate().catch(() => {})
if (!valid) return useMessage().warning("基础信息或库存必填项未填写完整")
if (!form.smErpUnitEntityList || form.smErpUnitEntityList.length <= 0) return useMessage().warning("请添加包装单位")
if (!(await packageUnitRef.value.editableTableValidate())) return useMessage().warning("包装单位必填项未填写完整")
if (!(await packageUnitRef.value.tableValidate())) return useMessage().warning("包装单位必填项未填写完整 且 相同包装单位的口味不能相同")
if (!packageUnitRef.value.getRadioRow()) return useMessage().warning("请选择基础包装单位")
// if (!form.smErpAuxiliaryCodeEntityList || form.smErpAuxiliaryCodeEntityList.length <= 0) return useMessage().warning("请添加辅助条码")
// if (!(await auxiliaryCodeRef.value.editableTableValidate())) return useMessage().warning("辅助条码必填项未填写完整")
console.log("未整理-包装单位", form.smErpUnitEntityList)
console.log("未整理-辅助条码", form.smErpAuxiliaryCodeEntityList)
const smErpAuxiliaryCodeEntityList = settleAuxiliaryCode()
const smErpUnitEntityList = settlePackageUnitList()
try {
loading.value = true
const _pa = {
...form,
...formatedBaseFormMoney.value,
...formatedStorePrice.value,
smErpAuxiliaryCodeEntityList,
smErpUnitEntityList,
}
console.log("提交的数据", _pa)
// console.log("提交的数据", _pa)
const res = form.id ? await putObj(_pa) : await addObj(_pa)
if (res.code === 0) {
@@ -1,110 +1,136 @@
<template>
<div class="layout-padding">
<div class="layout-padding-auto layout-padding-view">
<el-form v-show="showSearch" ref="queryRef" :inline="true" :model="state.queryForm" @keyup.enter="getDataList">
<el-form v-show="showSearch" ref="queryRef" :inline="true" :model="state.queryForm"
@keyup.enter="getDataList">
<el-row>
<el-form-item style="width: 300px" label="申请用户" prop="userIds">
<select-user v-model="state.queryForm.userIds" placeholder="申请用户" />
</el-form-item>
<el-form-item style="width: 300px" label="交款单位或个人" prop="deptOrUser">
<el-input v-model="state.queryForm.deptOrUser" clearable placeholder="交款单位或个人" />
</el-form-item>
<el-form-item style="width: 300px" label="发票状态" prop="userIds">
<dict-select v-model="state.queryForm.status" dict-code="recharge_invoice_status" />
</el-form-item>
<el-form-item style="width: 450px" label="创建时间" prop="createTimeList">
<el-date-picker v-model="state.queryForm.createTimeList" value-format="YYYY-MM-DD HH:mm:ss" type="datetimerange" />
<el-date-picker v-model="state.queryForm.createTimeList" value-format="YYYY-MM-DD HH:mm:ss"
type="datetimerange" />
</el-form-item>
<el-form-item style="width: 450px" label="审核时间" prop="processTimeList">
<el-date-picker v-model="state.queryForm.processTimeList" value-format="YYYY-MM-DD HH:mm:ss"
type="datetimerange" />
</el-form-item>
<el-form-item>
<el-button icon="Search" type="primary" @click="getDataList">{{ $t("common.queryBtn") }}</el-button>
<el-button icon="Search" type="primary" @click="getDataList">{{ $t("common.queryBtn") }}</el-button>
<el-button icon="Search" type="primary" @click="getDataList">{{ $t("common.queryBtn")
}}</el-button>
<el-button icon="Refresh" @click="resetQuery">{{ $t("common.resetBtn") }}</el-button>
</el-form-item>
</el-row>
</el-form>
<el-row>
<div class="mb8" style="width: 100%">
<el-button icon="folder-add" type="primary" class="ml10" @click="uploadExcelRef.show()" v-auth="'wallet_walletRechargeApply_add'">
<el-button icon="folder-add" type="primary" class="ml10" @click="uploadExcelRef.show()"
v-auth="'wallet_walletRechargeApply_add'">
导 入
</el-button>
<right-toolbar
v-model:showSearch="showSearch"
:export="'wallet_walletRechargeInvoice_export'"
@exportExcel="exportExcel"
class="ml10 mr20"
style="float: right"
@queryTable="getDataList"
></right-toolbar>
<div class="flex justify-between items-center">
<el-tabs class="flex-1" v-model="activeName" @tab-click="handleClickTabItem">
<el-tab-pane v-for="v in tabItems" :key="v.id" :label="v.label" :name="v.value" />
</el-tabs>
<right-toolbar v-model:showSearch="showSearch" :export="'wallet_walletRechargeInvoice_export'"
@exportExcel="exportExcel" class="ml10 mr20" style="float: right"
@queryTable="getDataList" />
</div>
</div>
</el-row>
<el-table
:data="state.dataList"
v-loading="state.loading"
border
:cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle"
@selection-change="selectionChangHandle"
@sort-change="sortChangeHandle"
>
<el-table :data="state.dataList" v-loading="state.loading" border :cell-style="tableStyle.cellStyle"
:header-cell-style="tableStyle.headerCellStyle" @selection-change="selectionChangHandle"
@sort-change="sortChangeHandle">
<el-table-column type="selection" width="40" align="center" />
<el-table-column type="index" label="#" width="50" />
<el-table-column prop="code" label="发票编号" />
<el-table-column prop="time" label="发票日期">
<el-table-column prop="code" min-width="100" label="发票编号" />
<el-table-column prop="time" min-width="120" label="发票日期">
<template #default="{ row }">
{{ parseTime(row.time, "{y}-{m}-{d}") }}
</template>
</el-table-column>
<el-table-column prop="deptOrUser" label="交款单位或个人" />
<el-table-column prop="totalPrice" label="合计人民币">
<el-table-column prop="deptOrUser" min-width="140" label="交款单位或个人" />
<el-table-column prop="totalPrice" min-width="120" label="合计人民币">
<template #default="{ row }">
{{ displayPrice(row.totalPrice) }}
</template>
</el-table-column>
<el-table-column prop="payeeUser" label="收款人" />
<el-table-column prop="payeeDept" label="收款单位" />
<el-table-column prop="status" label="发票状态">
<el-table-column prop="payeeUser" min-width="120" label="收款人" show-overflow-tooltip />
<el-table-column prop="payeeDept" min-width="120" label="收款单位" show-overflow-tooltip />
<el-table-column prop="processStatus" width="100" label="审核状态">
<template #default="{ row }">
<dict-tag :options="check_status" :value="row.processStatus" />
</template>
</el-table-column>
<el-table-column prop="status" label="发票状态" width="100">
<template #default="{ row }">
<dict-tag :options="recharge_invoice_status" :value="row.status" />
</template>
</el-table-column>
<el-table-column prop="payeeDept" label="发票下载">
<el-table-column prop="stampPicUrl" min-width="120" label="发票图片">
<template #default="{ row }">
<preview-image :src="row.picUrl" download :downloadName="`${row.deptOrUser}-${row.payeeDept}-发票-${row.updateTime}`" />
<preview-image :src="row.stampPicUrl" download
:downloadName="`${row.code}-${row.deptOrUser}-${row.payeeDept}-发票-${row.updateTime}`" />
</template>
</el-table-column>
<el-table-column prop="remark" label="备注" />
<el-table-column prop="createTime" width="200" label="创建时间" />
<el-table-column label="操作" width="200" fixed="right">
<el-table-column prop="remark" label="备注" show-overflow-tooltip />
<el-table-column width="250" label="时间">
<template #default="{ row }">
<el-button
v-auth="'wallet_walletRechargeApply_print'"
icon="printer"
text
type="primary"
:disabled="loading"
@click="previewInvoice(row)"
>
查看发票
</el-button>
<el-button icon="delete" text type="primary" v-auth="'wallet_walletRechargeInvoice_del'" @click="handleDelete([row.id])">
删除
</el-button>
<div class="flex justify-start">
<span>创建时间:</span>
<span>{{ row.createTime }} </span>
</div>
<div class="flex justify-start">
<span>申请时间:</span>
<span>{{ row.applyTime ?? "---" }} </span>
</div>
<div class="flex justify-start">
<span>审批时间:</span>
<span>{{ row.processTime ?? "---" }} </span>
</div>
</template>
</el-table-column>
<el-table-column label="操作" width="300" fixed="right">
<template #default="{ row }">
<div class="flex">
<el-button v-auth="'wallet_walletRechargeApply_print'" icon="printer" text type="primary"
:disabled="loading" @click="previewInvoice(row)">
查看发票
</el-button>
<!-- row.isCheckUser && -->
<el-button v-if="row.processStatus == '1'" type="primary" link icon="VideoPlay"
:disabled="loading" @click="deal(row)">
开始处理
</el-button>
<el-button icon="delete" text type="primary" v-auth="'wallet_walletRechargeInvoice_del'"
@click="handleDelete([row.id])">
删除
</el-button>
</div>
</template>
</el-table-column>
</el-table>
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle" v-bind="state.pagination" />
<pagination @size-change="sizeChangeHandle" @current-change="currentChangeHandle"
v-bind="state.pagination" />
</div>
<upload-excel
ref="uploadExcelRef"
title="导入"
url="/wallet/wallet-recharge-apply/read-topup-excel"
temp-url="/admin/sys-file/local/file/wallet_recharge.xlsx"
@refreshDataList="getDataList(false)"
/>
<upload-excel ref="uploadExcelRef" title="导入" url="/wallet/wallet-recharge-apply/read-topup-excel"
temp-url="/admin/sys-file/local/file/wallet_recharge.xlsx" @refreshDataList="getDataList(false)" />
<!-- 编辑、新增 -->
<form-dialog ref="formDialogRef" @refresh="getDataList(false)" />
<!-- 发票预览 -->
<print-dialog ref="printDialogRef" @refresh="getDataList(false)" />
<!-- 审批抽屉 -->
<process-drawer ref="processDrawerRef" @task-submit-event="taskSubmitEvent" />
</div>
</template>
@@ -116,21 +142,27 @@ import { displayPrice } from "/@/utils/formatMoney"
import { parseTime } from "/@/utils/formatTime"
import { useDict } from "/@/hooks/dict"
import { getObj } from "/@/api/wallet/wallet-recharge-invoice"
import ProcessDrawer from "/@/components/processDrawer/index.vue"
import { getDicts } from "/@/api/admin/dict"
// 引入组件
const FormDialog = defineAsyncComponent(() => import("./form.vue"))
const PrintDialog = defineAsyncComponent(() => import("./print-dialog.vue"))
const { recharge_invoice_status } = useDict("recharge_invoice_status")
const { recharge_invoice_status, check_status } = useDict("recharge_invoice_status", "check_status")
// 定义变量内容
const formDialogRef = ref()
const uploadExcelRef = ref()
// 搜索变量
const queryRef = ref()
const processDrawerRef = ref()
const showSearch = ref(true)
// 多选变量
const selectObjs = ref([]) as any
const multiple = ref(true)
const activeName = ref()
const tabItems = ref<any>([{}])
const state: BasicTableProps = reactive<BasicTableProps>({
queryForm: {},
@@ -146,6 +178,7 @@ const { getDataList, currentChangeHandle, sizeChangeHandle, sortChangeHandle, do
const resetQuery = () => {
// 清空搜索条件
queryRef.value?.resetFields()
state.queryForm.processStatus = ""
// 清空多选
selectObjs.value = []
getDataList()
@@ -162,6 +195,19 @@ const selectionChangHandle = (objs: { id: string }[]) => {
multiple.value = !objs.length
}
onMounted(async () => {
const { data } = await getDicts("check_status")
data.unshift({ label: "全部", value: null })
data.push({ label: "未提交", value: 99 })
tabItems.value = data
})
// tab点击切换
const handleClickTabItem = (e: any) => {
state.queryForm.processStatus = tabItems.value[e.index].value
getDataList()
}
// 删除操作
const handleDelete = async (ids: string[]) => {
try {
@@ -193,4 +239,15 @@ const previewInvoice = async (row: any) => {
loading.value = false
}
}
// 执行审批
const deal = (row: any) => {
if (!row.processId) return useMessage().info("流程id不存在")
processDrawerRef.value.openProcessDrawer(row)
}
// 审批提交
const taskSubmitEvent = () => {
getDataList()
}
</script>
@@ -1,6 +1,8 @@
<template>
<el-dialog v-model="visible" title="预览" width="800px" :close-on-click-modal="false" draggable destroy-on-close>
<div id="receiptRef" ref="receiptRef" class="w-[17.5cm] h-[9.5cm] border border-gray-400 p-6 bg-[#EBE1C622]">
<dict-tag class="mb-2" :options="check_status" :value="receiptData.processStatus" />
<div v-loading="loading" id="receiptRef" ref="receiptRef" class="w-[17.5cm] h-[9.5cm] border border-gray-400 p-6 bg-[#EBE1C622]">
<div class="text-center mx-auto w-[10cm] text-3xl font-bold">浦江县行政事业单位食堂统一收款收据</div>
<div class="flex justify-between items-end mb-1">
@@ -24,6 +26,7 @@
v-model="receiptData.deptOrUser"
class="caret-red-600 w-full h-full bg-transparent text-center"
ref="deptOrUserInput"
maxlength="30"
/>
</td>
</tr>
@@ -61,15 +64,14 @@
<td class="border border-gray-600 px-2 w-1/6 h-[0.75cm]">收款单位<br />(盖章)</td>
<td class="border border-gray-600 px-2 text-left w-1/6 h-[0.75cm] text-sm text-blue-800">
<!-- <input type="text" v-model="receiptData.payeeDept" class="w-full h-full bg-transparent" /> -->
<img
v-if="receiptData.picUrl || isStamping"
<!-- <img
class="w-[2.5cm] h-[2.5cm] absolute -top-2 left-[140px]"
:class="{ stamping: isStamping }"
draggable="false"
style="-webkit-user-drag: none; user-select: none; pointer-events: none"
oncontextmenu="return false"
src="/@/assets/receiptStamp.png"
/>
/> -->
</td>
<td class="border border-gray-600 px-2 w-1/6 h-[0.75cm]">开票人<br />(签名)</td>
<td class="border border-gray-600 px-2 text-left w-1/6 h-[0.75cm] text-sm text-blue-800">
@@ -81,7 +83,8 @@
<span class="whitespace-nowrap">备注:</span>
<textarea
v-model="receiptData.remark"
class="flex-1 text-sm text-blue-800 w-full h-full my-1 bg-transparent resize-none overflow-y-hidden"
maxlength="12"
class="flex-1 text-sm text-blue-800 w-full h-full bg-transparent resize-none overflow-y-hidden"
/>
</div>
</td>
@@ -95,21 +98,9 @@
</div>
</div>
<div class="h-6">
<el-progress
:percentage="progressPercent"
v-if="progressPercent > 30"
:stroke-width="6"
status="success"
striped
striped-flow
:duration="20"
/>
</div>
<template #footer>
<el-button @click="handleClose" :disabled="loading">关闭</el-button>
<el-button
<!-- <el-button
v-if="!receiptData.picUrl"
v-auth="'wallet_walletRechargeApply_receiptStamp'"
type="primary"
@@ -117,19 +108,20 @@
:disabled="loading"
>
盖章
</el-button>
</el-button> -->
<el-button
v-if="receiptData.picUrl"
v-if="receiptData.processStatus == '2' || receiptData.processStatus == '3'"
v-auth="'wallet_walletRechargeApply_back'"
type="primary"
plain
@click="backInvoice"
:disabled="loadingBack"
:disabled="loading"
>
作废
</el-button>
<el-button v-if="!receiptData.processStatus" type="primary" :disabled="loading" @click="applyStamp">申请审批</el-button>
<el-button v-auth="'wallet_walletRechargeApply_receiptSave'" type="primary" @click="saveReceipt" :disabled="loading">保存</el-button>
<el-button v-if="receiptData.picUrl" type="primary" @click="handlePrint" :disabled="loading">打印</el-button>
<el-button v-if="receiptData.stampPicUrl" type="warning" @click="handlePrint" :disabled="loading">打印</el-button>
</template>
</el-dialog>
</template>
@@ -142,9 +134,8 @@ import request from "/@/utils/request"
import { formatDate } from "/@/utils/formatTime"
import { displayPrice } from "/@/utils/formatMoney"
import printJS from "print-js"
import { bindInvoice, invoiceBack, getObj } from "/@/api/wallet/wallet-recharge-invoice"
const emit = defineEmits(["refresh"])
import { bindInvoice, invoiceBack, getObj, apply } from "/@/api/wallet/wallet-recharge-invoice"
import { useDict } from "/@/hooks/dict"
interface ReceiptData {
id: string
@@ -158,14 +149,18 @@ interface ReceiptData {
remark: string
totalPriceCnStr: string
picUrl: string
stampPicUrl: string
processStatus: string | null
}
const emit = defineEmits(["refresh"])
const { check_status } = useDict("check_status")
let timer
const visible = ref(false)
const loading = ref(false)
const loadingBack = ref(false)
const receiptRef = ref<HTMLElement | null>(null)
const deptOrUserInput = ref<HTMLInputElement | null>(null)
let timer
const isStamping = ref(false) // 盖章动画开关
const receiptData = ref<ReceiptData>({
id: "",
@@ -179,9 +174,9 @@ const receiptData = ref<ReceiptData>({
payeeUser: "", // 开票人
remark: "", // 备注
picUrl: "", // 发票图片地址
stampPicUrl: "", // 盖过章的发票图片地址
processStatus: "", // 审批状态
})
const applyId = ref<string>()
const progressPercent = ref(30)
const receiptDataItems = computed(() => {
try {
const itemJson = JSON.parse(receiptData.value.itemJson)
@@ -198,7 +193,7 @@ const totalPrice = computed(() => displayPrice(receiptData.value.totalPrice))
const openDialog = (data: ReceiptData, id: string) => {
visible.value = true
receiptData.value = data
applyId.value = id
receiptData.value.id = id
isStamping.value = false
timer = setTimeout(() => {
deptOrUserInput.value?.focus()
@@ -212,11 +207,7 @@ const handleClose = () => {
// 发票作废
const backInvoice = async () => {
if (!receiptData.value.picUrl) {
useMessage().error("请先盖章")
return
}
loadingBack.value = true
loading.value = true
try {
await invoiceBack({ id: receiptData.value.id })
const res = await getObj(receiptData.value.id)
@@ -227,7 +218,7 @@ const backInvoice = async () => {
console.error(error)
useMessage().error(error.msg)
} finally {
loadingBack.value = false
loading.value = false
}
}
@@ -251,50 +242,36 @@ const genImage = async (): Promise<Blob | void | null> => {
// 图片上传
const uploadImage = async (blob: Blob): Promise<string | void> => {
try {
loading.value = true
const formData = new FormData()
formData.append("file", blob, "receipt.png")
const { code, data } = await request({
url: "/admin/sys-file/upload",
method: "post",
headers: {
"Content-Type": "multipart/form-data",
},
data: formData,
onUploadProgress: (progressEvent: any) => {
if (progressEvent.lengthComputable) {
progressPercent.value = Math.round((progressEvent.loaded * 100) / progressEvent.total)
}
},
})
if (code == 0) return data.url
useMessage().error(data.msg || "上传失败")
} catch (error) {
useMessage().error(error as string)
} finally {
loading.value = false
progressPercent.value = 30
isStamping.value = false
}
const formData = new FormData()
formData.append("file", blob, "receipt.png")
const { code, data } = await request({
url: "/admin/sys-file/upload",
method: "post",
headers: {
"Content-Type": "multipart/form-data",
},
data: formData,
})
if (code == 0) return data.url
useMessage().error(data.msg || "上传失败")
}
// 盖章并上传发票图片并保存
const stampReceipt = () => {
loading.value = true
isStamping.value = true
// const stampReceipt = () => {
// loading.value = true
// isStamping.value = true
timer = setTimeout(async () => {
const blob = await genImage()
if (blob) {
const url = await uploadImage(blob)
if (url) {
receiptData.value.picUrl = url
await saveReceipt()
}
}
}, 1030)
}
// timer = setTimeout(async () => {
// const blob = await genImage()
// if (blob) {
// const url = await uploadImage(blob)
// if (url) {
// receiptData.value.picUrl = url
// await saveReceipt()
// }
// }
// }, 1030)
// }
// 保存发票
const saveReceipt = async (): Promise<void> => {
@@ -303,7 +280,7 @@ const saveReceipt = async (): Promise<void> => {
const { code, data } = await bindInvoice({
...receiptData.value,
deptOrUser: receiptData.value.deptOrUser,
applyId: applyId.value,
applyId: receiptData.value.id,
})
if (code == 0) {
emit("refresh")
@@ -318,6 +295,33 @@ const saveReceipt = async (): Promise<void> => {
}
}
// 申请盖章审批
const applyStamp = async () => {
await useMessage().delConfirm("是否提交审批")
if (receiptData.value.processStatus == "1") return useMessage().warning("你已提交过申请,请勿重复提交")
loading.value = true
try {
const blob = await genImage()
if (!blob) return useMessage().success("图片生成失败")
const picUrl = await uploadImage(blob)
if (!picUrl) return useMessage().success("图片上传失败")
const { code, msg } = await apply({ id: receiptData.value.id, picUrl })
if (code == 0) {
useMessage().success("申请成功")
emit("refresh")
visible.value = false
return
}
useMessage().error(msg || "申请失败")
} catch (error) {
useMessage().error(error as string)
} finally {
loading.value = false
}
}
// 打印
const handlePrint = async () => {
if (receiptRef.value) {