web/src/components/inventory/goods/Edit.vue

925 lines
32 KiB
Vue

<template>
<Mask :is-show="isShow" :height="900" @close="exit" title="新增" :show-footer="true">
<template #default>
<el-scrollbar>
<div class="header">
<span class="default-btn" style="margin:10px auto" @click="openCreateSearch" v-if="_type!=0">一键建档 </span>
</div>
<div class="common-layout">
<el-container>
<el-aside width="800px">
<div class="body">
<el-form ref="formRef"
:model="edit_data"
:rules="rules" style="width: 100%">
<el-descriptions title="基础" border direction="vertical">
<el-descriptions-item label="名称">
<el-form-item label="" prop="name" class="form-item">
<el-input v-model="edit_data.name"/>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="通用名">
<el-form-item label="" prop="commonName" class="form-item">
<el-input v-model="edit_data.commonName"/>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="类型" style="display: flex">
<el-form-item label="" class="form-item">
<el-select v-model="edit_data.cateId" placeholder="请选择" style="width: 70%">
<el-option
v-for="item in cate_list"
:key="item.id"
:label="item.name"
:value="item.id">
</el-option>
</el-select>
<el-button @click="showCateEdit">
<el-icon>
<Setting/>
</el-icon>
</el-button>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="进口|国产" v-if="_type==1306">
<el-select
v-model="edit_data.extra.maintainCate"
placeholder="进口|国产"
clearable
style="width: 240px"
>
<el-option
v-for="item in imported"
:key="item.label"
:label="item.label"
:value="item.label"
/>
</el-select>
</el-descriptions-item>
<el-descriptions-item label="效期预警(天)">
<el-form-item lable="" prop="expiryWarnDays" class="form-item">
<el-input-number v-model="edit_data.expiryWarnDays" class="input" style="width: 100%;" :min="0">
</el-input-number>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="库存预警">
<el-form-item lable="" prop="inventoryWarnNumber" class="form-item">
<el-input-number v-model="edit_data.inventoryWarnNumber" class="input" style="width: 100%;"
:min="0">
</el-input-number>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="批准文号" v-if="_type==1301 || _type==1306 || _type == 0">
<el-form-item lable="" prop="approvalCode" class="form-item">
<el-input v-model="edit_data.approvalCode" class="input">
</el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="生产企业" v-if="_type!=1302">
<el-form-item label="" prop="producer" class="form-item">
<el-input v-model="edit_data.producer"/>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="注册证名称" v-if="_type==1306">
<el-form-item>
<el-input v-model="edit_data.extra.registrationCertificateName" class="input">
</el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="条形码" v-if="_type == 1301 || _type == 1302 || _type==0">
<el-form-item>
<el-input v-model="edit_data.barcode"/>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="规格" v-if="_type==1302||_type==1306||_type==0">
<el-form-item>
<el-input v-model="edit_data.specification" class="input">
</el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="最小制剂数量|单位" v-if="_type==1301">
<el-form-item>
<div class="unit-item">
<el-input ref="medicineDosageRef" v-model="edit_data.medicineDosageNum" class="input"
style="width: 200px;">
</el-input>
<el-popover
placement="bottom"
title="Title"
:width="200"
trigger="click"
>
<template #reference>
<div class="unit">{{ edit_data.medicineDosageUnit }}</div>
</template>
<UnitSelector :units="dosageUnitList" v-model="edit_data.medicineDosageUnit"></UnitSelector>
</el-popover>
</div>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="最小包装数量|单位">
<el-form-item>
<div class="unit-item">
<el-input ref="minPackagingRef" v-model="edit_data.minPackagingNumber" type="number"
class="input"
style="width: 200px;">
</el-input>
<el-popover
placement="bottom"
title="Title"
:width="200"
trigger="click"
>
<template #reference>
<div class="unit">{{ edit_data.minPackagingUnit }}</div>
</template>
<UnitSelector :units="packagingUnit" v-model="edit_data.minPackagingUnit"></UnitSelector>
</el-popover>
</div>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="包装单位">
<el-form-item>
<div class="unit-item">
<el-popover
placement="bottom"
title="Title"
:width="200"
trigger="click"
>
<template #reference>
<div class="unit" style="width: 232px">{{ edit_data.packagingUnit }}</div>
</template>
<UnitSelector :units="packagingUnit" v-model="edit_data.packagingUnit"></UnitSelector>
</el-popover>
</div>
</el-form-item>
</el-descriptions-item>
<!-- <el-descriptions-item :label="_type==1301?'国药准字':'国械注准'" v-if="_type==1301 || _type==1306">-->
<!-- <el-input v-model="edit_data.approvalCode"/>-->
<!-- </el-descriptions-item>-->
<el-descriptions-item label="注册剂型" v-if="_type==1301">
<el-form-item>
<el-input v-model="edit_data.extra.regType" class="input">
</el-input>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="药品标识码" v-if="_type==1301">
<el-form-item>
<el-popover
:visible="showPopover"
placement="bottom"
:width="200"
id="code-pop"
class="code-popo"
>
<div style="color: #6c6b6b;font-size: 12px">已关联({{
idCodeList ? idCodeList.length : 0
}})
</div>
<Divider/>
<div class="item">
<div v-for="(item,index) in idCodeList" :key="index">
<div class="remove">
<el-icon @click="removeIdCode(item)" id="code-remove">
<Close/>
</el-icon>
</div>
<div style="width: 70%" class="text">
{{ item }}
</div>
</div>
</div>
<template #reference>
<el-input v-model="idCode" id="code-input" @keydown.enter="addIdCode"
@click="clickIdCodeInput"></el-input>
</template>
</el-popover>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="标签">
<el-form-item>
<el-input-tag
draggable
v-model="edit_data.tags"
class="input"
>
</el-input-tag>
</el-form-item>
</el-descriptions-item>
<el-descriptions-item label="备注">
<el-form-item>
<el-input v-model="edit_data.remark" class="input"/>
</el-form-item>
</el-descriptions-item>
</el-descriptions>
<el-descriptions title="扩展" border style="margin-top: 20px" direction="vertical">
<el-descriptions-item label="养护分类" v-if="_type != 0">
<el-select
v-model="edit_data.extra.maintainCate"
placeholder="选择养护分类"
clearable
style="width: 240px"
>
<el-option
v-for="item in maintainOptions"
:key="item.label"
:label="item.label"
:value="item.label"
/>
</el-select>
</el-descriptions-item>
<el-descriptions-item label="医疗器械分类" v-if="_type==1306">
<el-select
v-model="edit_data.extra.instrumentCategroy"
placeholder="选择医疗器械分类"
clearable
style="width: 240px"
>
<el-option
v-for="item in instrumentCategroyOptions"
:key="item.label"
:label="item.label"
:value="item.label"
/>
</el-select>
</el-descriptions-item>
<el-descriptions-item label="储存条件" v-if="_type != 0">
<el-select
v-model="edit_data.extra.storageConditions"
placeholder="选择储存条件"
clearable
style="width: 240px;"
>
<el-option
v-for="item in storageConditionsOptions"
:key="item.label"
:label="item.label"
:value="item.label"
/>
</el-select>
</el-descriptions-item>
<el-descriptions-item label="保质期" v-if="_type != 0">
<el-input v-model="edit_data.expiryTime" type="number">
<template #append>月</template>
</el-input>
</el-descriptions-item>
<el-descriptions-item label="柜号">
<el-input v-model="edit_data.extra.cabinetNumber">
</el-input>
</el-descriptions-item>
<!-- <el-descriptions-item label="用法用量" v-if="_type==1301">-->
<!-- <el-input v-model="edit_data.extra.usage">-->
<!-- </el-input>-->
<!-- </el-descriptions-item>-->
<el-descriptions-item label="处方药/OTC" v-if="_type==1301">
<el-select
v-model="edit_data.extra.drugCategory"
placeholder="选择药品分类"
clearable
style="width: 240px"
>
<el-option
v-for="item in drugCategoryOptions"
:key="item.label"
:label="item.label"
:value="item.label"
/>
</el-select>
</el-descriptions-item>
<el-descriptions-item label="精麻毒放|麻黄碱" v-if="_type==1301">
<el-select
v-model="edit_data.extra.JMDF"
placeholder="选择精麻毒放|麻黄碱"
clearable
style="width: 240px"
>
<el-option
v-for="item in JMDFList"
:key="item.label"
:label="item.label"
:value="item.label"
/>
</el-select>
</el-descriptions-item>
<el-descriptions-item label="抗菌药物|DDD值" v-if="_type==1301">
<div class="antibacterial-agents">
<el-select
v-model="edit_data.extra.isAntibacterialAgents"
clearable
style="width: 100px"
>
<el-option
v-for="item in isAntibacterialAgentsOptions"
:key="item.label"
:label="item.label"
:value="item.label"
/>
</el-select>
<el-input v-model="edit_data.extra.DDD" style="width: 80px"/>
<div class="unit-item">
<el-popover
placement="bottom"
title="Title"
:width="200"
trigger="click"
>
<template #reference>
<div class="unit" style="width: 232px">{{ edit_data.extra.DDDUnit }}</div>
</template>
<UnitSelector :units="DDDUnitList" v-model="edit_data.extra.DDDUnit"></UnitSelector>
</el-popover>
</div>
</div>
</el-descriptions-item>
<el-descriptions-item label="基药" v-if="_type==1301">
<el-select
v-model="edit_data.extra.baseMedicine"
placeholder="选择基药"
clearable
style="width: 240px"
>
<el-option
v-for="item in baseMedicineOptions"
:key="item.label"
:label="item.label"
:value="item.label"
/>
</el-select>
</el-descriptions-item>
<el-descriptions-item label="上市许可持有人" v-if="_type != 0">
<el-input v-model="edit_data.extra.authorizationMaster"></el-input>
</el-descriptions-item>
</el-descriptions>
</el-form>
</div>
</el-aside>
<el-aside width="350px" style="border-left: 1px #ddd solid">
<el-form style="width: 100%;" :rules="rules" ref="formRef" label-width="100px">
<el-descriptions title="定价" border direction="vertical" :column="2" style="margin-left: 5px">
<el-descriptions-item label="进价参考" width="180">
<el-input v-model.number="edit_data.purchaseUnitPrice" type="number" :min="1">
<template #prefix></template>
</el-input>
</el-descriptions-item>
<el-descriptions-item label="定价模式">
<el-select v-model="edit_data.pricingModel" placeholder="请选择">
<el-option
v-for="item in pricingModelOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-descriptions-item>
<el-descriptions-item label="加成率" v-if="edit_data.pricingModel==1" width="180">
<el-input v-model="edit_data.makeUp" type="number">
<template #append>%</template>
</el-input>
</el-descriptions-item>
<el-descriptions-item label="零售价格" v-else>
<el-input v-model="edit_data.unitPrice" type="number"
>
<template #prefix>¥</template>
<template #append>/{{ edit_data.packagingUnit }}</template>
</el-input>
</el-descriptions-item>
<el-descriptions-item>
<template #label>
<el-checkbox v-model="edit_data.trdnFlag" label="是否允许拆零" size="large"/>
</template>
<el-input v-model="edit_data.disassemblyPrice" type="number" :disabled="!edit_data.trdnFlag">
<template #prefix>¥</template>
<template #append>/{{ edit_data.minPackagingUnit }}</template>
</el-input>
</el-descriptions-item>
</el-descriptions>
<el-descriptions title="医保" border direction="vertical" :column="1" style="margin-left: 5px"
v-if="_type !=0">
<el-descriptions-item label="医保对码">
<SocialInfo v-model="edit_data.hilistCode"
@openSearch="openContrastCodeSearch"></SocialInfo>
</el-descriptions-item>
</el-descriptions>
</el-form>
</el-aside>
</el-container>
</div>
</el-scrollbar>
</template>
<template #footer>
<div class="footer">
<span class="small-btn" @click="returnInit"
v-if="edit_data.id != null">医保库存重新初始化</span>
<span class="danger-btn" v-if="edit_data.saleStatus" @click="disableSale">停售</span>
<span class="danger-btn" v-else @click="enableSale">起售</span>
<span class="small-btn" @click="save(true)">保存</span>
<span class="small-btn" @click="save(false)" v-if="edit_data.id == null">保存并继续</span>
<span class="small-btn" @click="exit">关闭</span>
</div>
</template>
</Mask>
<!-- 新增关闭按钮 -->
<Search ref="createSearchRef" @confirm="createConfirm"/>
<Search ref="contrastCodeSearch" @confirm="contrastCodeConfirm"/>
<Cate :type="_type" @close="cateCloseCallBack" ref="cateRef"/>
</template>
<script setup lang="ts">
import {nextTick, ref, watch} from "vue";
import {dosageUnitList, packagingUnit, DDDUnitList} from "@/utils/unitList.ts"
import {Setting, Close} from "@element-plus/icons-vue";
import Mask from "@/components/common/Mask.vue";
import Search from "@/components/inventory/goods/Search.vue";
import {post} from "@/utils/request.ts";
import Cate from "@/components/inventory/goods/Cate.vue";
import {ElMessage, ElMessageBox} from "element-plus";
import Divider from "@/components/Divider.vue";
import UnitSelector from "@/components/inventory/goods/UnitSelector.vue";
import SocialInfo from "@/components/inventory/goods/SocialInfo.vue";
import {API} from "@/assets/config/API.ts";
let _type = ref(0);
let type = ref(0);
const isShow = ref<any>(false)
const imported = [{
label: '进口',
}, {label: '国产'}]
const pricingModelOptions = [
{
label: '进价加成',
value: 1,
}, {
label: '固定售价',
value: 0,
}
]
const isAntibacterialAgentsOptions = [
{
label: '非限制使用级',
},
{
label: '限制使用级',
},
{
label: '特殊使用级',
}
]
const baseMedicineOptions = [
{
label: '国家基药',
},
{
label: '地标基药',
}
]
const JMDFList = [
{
label: '精I',
},
{
label: '精II',
},
{
label: '麻',
},
{
label: '毒',
},
{
label: '放',
},
{
label: '麻黄碱',
}
]
const maintainOptions = [
{
label: '一般养护',
},
{
label: '重点养护',
},
{
label: '无需养护',
}
]
const storageConditionsOptions =
[
{
label: '常温',
}
,
{
label: '阴凉',
}
,
{
label: '冷藏',
}
,
{
label: '冷冻',
}
,
{
label: '避光',
}
,
{
label: '密封',
}
]
const instrumentCategroyOptions = [
{
label: '一类',
},
{
label: '二类',
},
{
label: '三类',
}
]
const emit = defineEmits(['close'])
let edit_data: any = ref({
trdnFlag: false,
extra: {},
minPackagingUnit: "只",
packagingUnit: "盒",
pricingModel: 0,
expiryWarnDays: 0,
inventoryWarnNumber: 0,
purchaseUnitPrice: 1
});
const initEditData = () => {
edit_data.value = {
trdnFlag: false,
extra: {},
minPackagingUnit: "只",
packagingUnit: "盒",
pricingModel: 0,
expiryWarnDays: 0,
inventoryWarnNumber: 0,
purchaseUnitPrice: 1
}
}
const idCode = ref("");
const showPopover = ref(false);
const idCodeList = ref<string[]>([]);
const addIdCode = () => {
let index = idCodeList.value.indexOf(idCode.value);
if (index != -1) {
ElMessage({
message: '编码已存在',
type: 'warning',
plain: true,
})
return
}
if (idCode.value.length < 7 && (_type.value == 1301 || _type.value == 1302)) {
ElMessage({
message: '最少7位',
type: 'warning',
plain: true,
})
return
}
if (idCode.value.length > 7 && (_type.value == 1301 || _type.value == 1302)) {
idCode.value = idCode.value.substring(0, 7);
}
idCodeList.value.push(idCode.value);
idCode.value = "";
showPopover.value = true;
}
const removeIdCode = (item: string) => {
let index = idCodeList.value.indexOf(item);
if (index != -1) {
idCodeList.value.splice(index, 1)
}
showPopover.value = idCodeList.value.length > 0;
}
const init = (type: number, id: number) => {
isShow.value = true
_type.value = type;
if (id != null && id != 0) {
post(API.Goods.Base.Get, {id: id}).then((res: any) => {
edit_data.value = res;
edit_data.value.tags = edit_data.value.tags ? edit_data.value.tags.split(",") : null;
edit_data.value.extra = JSON.parse(edit_data.value.extra);
edit_data.value.trdnFlag = edit_data.value.trdnFlag ? edit_data.value.trdnFlag == 1 : false;
idCodeList.value = edit_data.value.idCode ? edit_data.value.idCode.split(",") : [];
idCode.value = idCodeList.value.length > 0 ? idCodeList.value.length + "项" : "";
getHilistInfo()
})
}
getCateList()
document.addEventListener("click", handleClickOutside);
};
defineExpose({init});
const createSearchRef = ref<InstanceType<typeof Search>>();
const openCreateSearch = () => {
nextTick(() => {
createSearchRef.value?.init(_type.value, edit_data.value.name);
});
}
const createConfirm = (data: any) => {
if (_type.value == 1301) {
edit_data.value.name = data.name
edit_data.value.hilistCode = data.hilistCode
edit_data.value.approvalCode = data.approvalCode
edit_data.value.producer = data.producer
edit_data.value.packagingUnit = data.packagingUnit
edit_data.value.minPackagingNumber = data.minPackagingNumber
edit_data.value.minPackagingUnit = data.minPackagingUnit
edit_data.value.medicineDosageUnit = data.medicineDosageUnit
edit_data.value.medicineDosageNumber = data.medicineDosageNumber
edit_data.value.extra = data.extra
} else if (_type.value == 1302) {
edit_data.value.name = data.name
edit_data.value.hilistCode = data.hilistCode
edit_data.value.commonName = data.commonName
edit_data.value.packagingUnit = "g"
edit_data.value.minPackagingNumber = 1
edit_data.value.minPackagingUnit = "g"
} else if (_type.value == 1306) {
edit_data.value.name = data.name
edit_data.value.hilistCode = data.hilistCode
edit_data.value.commonName = data.commonName
edit_data.value.approvalCode = data.approvalCode
edit_data.value.producer = data.producer
edit_data.value.specification = data.specification
edit_data.value.packagingUnit = data.packagingUnit
edit_data.value.minPackagingUnit = data.minPackagingUnit
edit_data.value.medicineDosageUnit = data.medicineDosageUnit
edit_data.value.medicineDosageNumber = data.medicineDosageNumber
}
}
const contrastCodeSearch = ref()
const openContrastCodeSearch = () => {
nextTick(() => {
contrastCodeSearch.value?.init(_type.value, edit_data.value.name);
});
}
const contrastCodeConfirm = (data: any) => {
edit_data.value.hilistCode = data.hilistCode
}
// 添加表单校验
const rules = ref({
name: [
{required: true, message: '商品名称不能为空', trigger: 'blur'},
],
cateId: [
{required: true, message: '请选择商品类型', trigger: 'change'}
],
approvalCode: [
{required: true, message: '批准文号不能为空', trigger: 'blur'}
],
purchaseUnitPrice: [
{type: 'number', message: '必须为数字', trigger: 'blur'},
],
producer: [
{required: true, message: '生产企业不能为空', trigger: 'blur'}
],
makeUp: [
{required: true, message: '不能为空', trigger: 'blur'}
],
unitPrice: [
{type: 'number', message: '不能为空', trigger: 'blur'},
]
})
let save = async (isClose: Boolean) => {
try {
await formRef.value.validate()
if (!edit_data.value.purchaseUnitPrice || edit_data.value.purchaseUnitPrice < 1) {
ElMessage.error('参考进价不能为空或小于1');
return
}
const data = JSON.parse(JSON.stringify(edit_data.value));
data.tags = data.tags ? data.tags.join(",") : null;
data.idCode = idCodeList.value.join(",");
data.type = _type.value;
post(API.Goods.Base.Save, data).then((res: any) => {
ElMessage.success('保存成功')
if (isClose) {
//关闭该页面
exit()
return
}
//重置该界面
initEditData()
})
// ...原有保存逻辑...
} catch (e) {
ElMessage.error('请正确填写表单内容')
}
}
//获取分类列表
const cate_list: any = ref([]);
const getCateList = () => {
post(API.Goods.Cate.List, {type: _type.value}).then((res: any) => {
cate_list.value = res
})
}
const cateRef = ref()
const showCateEdit = () => {
cateRef.value.init(cate_list.value)
}
const cateCloseCallBack = () => {
getCateList()
}
let exit = () => {
document.addEventListener("click", handleClickOutside);
isShow.value = false
initEditData()
emit('close');
}
const handleClickOutside = (event: MouseEvent) => {
const target = event.target as HTMLElement;
if (!target.closest('#code-pop') && !target.closest('#code-input') && !target.closest('#code-remove')) {
showPopover.value = false;
idCode.value = idCodeList.value.length > 0 ? idCodeList.value.length + "项" : "";
}
}
const clickIdCodeInput = () => {
showPopover.value = true
idCode.value = ""
}
const returnInit = () => {
ElMessageBox.confirm(
`确定要重新初始化医保库存码?`,
'提升',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
post(API.Goods.Base.ReturnInit, {id: edit_data.value.id})
})
}
// 修改保存逻辑
const formRef = ref()
const hilistInfo = ref<any>({})
const getHilistInfo = () => {
if (edit_data.value.hilistCode) {
post(API.Social.Directory.GetByCode, {code: edit_data.value.hilistCode}).then((res: any) => {
hilistInfo.value = res
type.value = res.type
})
}
}
watch(() => edit_data.value.hilistCode, (newVal) => {
if (newVal) {
getHilistInfo()
}
})
const drugCategoryOptions = [
{
label: '处方药',
value: 1
},
{
label: '非处方药',
value: 2
},
]
const disableSale = () => {
ElMessageBox.confirm(
`确定要下架该商品吗?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
post(API.Goods.Base.DisableSale, {id: edit_data.value.id}).then((res: any) => {
ElMessage.success("下架成功")
exit()
})
})
}
const enableSale = () => {
ElMessageBox.confirm(
`确定要起售该商品吗?`,
'提示',
{
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
post(API.Goods.Base.EnableSale, {id: edit_data.value.id}).then((res: any) => {
ElMessage.success("启用成功")
exit()
})
})
}
</script>
<style scoped lang="scss">
.header {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
}
.common-layout {
margin-top: 10px;
padding: 0 24px 24px;
.antibacterial-agents {
display: flex;
.unit-item {
display: flex;
width: 50px;
.unit {
width: 32px;
height: 32px;
border: 1px #ddd solid;
color: #818080;
display: flex;
align-items: center;
justify-content: center;
}
}
}
}
.item {
margin-top: 5px;
.text {
font-weight: bold;
}
.remove {
font-size: 16px;
position: absolute;
right: 15px;
&:hover {
color: #2e7eb3;
}
}
}
.unit-item {
display: flex;
.unit {
width: 32px;
height: 32px;
border: 1px #ddd solid;
color: #818080;
display: flex;
align-items: center;
justify-content: center;
}
}
.footer {
height: 100%;
display: flex;
justify-content: flex-end;
align-items: center;
padding: 0 24px;
}
</style>