| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564 |
- <script lang="ts" setup>
- import { ref, watch } from 'vue';
- import { Form, message } from 'ant-design-vue';
- import { PlusOutlined } from '@ant-design/icons-vue'; // 确保导入
- import VxeUI from 'vxe-table';
- import { useRequest } from 'alova/client';
- import { getDictionaryMethod, cpMedicinesMethod } from '@/request/api/dictionary.api';
- import { branchMethod } from '@/request/api/system.api';
- import { systemCpEditMethod, getAllSupplierMethod, getConditioningSchemeDetailMethod } from '@/request/api/care.api';
- import { UploadIFile } from '@/request/api/follow.api';
- import type { SystemItemModel } from '@/model/care.model';
- import RemoteSelect from '@/libs/v-select-page/RemoteSelect.vue';
- import type { UploadFile } from 'ant-design-vue/es/upload/interface';
- import type { FormInstance } from 'ant-design-vue';
- type SystemModel = Partial<SystemItemModel>;
- const props = defineProps<{ data: SystemModel }>();
- const formRef = ref<FormInstance>();
- const typeOptionsLoading = ref<boolean>(false);
- const typeOptions = ref<{ label: string; value: string }[]>([]);
- const supplierOptions = ref<{ label: string; value: string }[]>([]);
- const isRequired = ref<boolean>(true);
- const unitOptions = [
- { label: '袋', value: '袋' },
- { label: '包', value: '包' },
- { label: '贴', value: '贴' },
- { label: '次', value: '次' },
- ];
- // 获取所有的机构
- const branch = ref<any[]>([]);
- const { loading: branchLoading } = useRequest(branchMethod).onSuccess(({ data }) => {
- const to = (data?: any[]): any[] => {
- return Array.isArray(data)
- ? data.map((item) => {
- return {
- ...item,
- value: item.id,
- key: item.id.toString(),
- children: to(item.children),
- };
- })
- : [];
- };
- branch.value = to(data);
- });
- const form = reactive<SystemModel>({
- institutionName: '',
- conditioningProgramType: '',
- conditioningProgramSupplierId: '',
- institutionId: '',
- cpDynamicPricingRule: [
- { min: 0, max: 0, priceType: 0, price: 0 },
- { min: 0, max: 0, priceType: 0, price: 0 },
- ],
- pricingType: '0',
- cpFixedPricingRule: {
- unitPrice: 0,
- pricingUnit: '',
- convertDose: 0,
- convertUnit: '',
- },
- cpMedicines: [{ name: '', dosage: '', id: '' }],
- isOffline: null,
- isDelivery: null,
- });
- const onlineArr = ref<string[]>([]);
- const deliverArr = ref<string[]>([]);
- const rules = {
- name: [{ required: true, message: '请输入项目名称', trigger: 'blur' }],
- conditioningProgramType: [{ required: true, message: '请选择方案类型', trigger: 'change' }],
- pricingType: [{ required: true, message: '请选择计价规则', trigger: 'change' }],
- conditioningProgramSupplierId: [{ required: true, message: '请选择供应商', trigger: 'change' }],
- institutionId: [{ required: true, message: '请选择机构名称', trigger: 'change' }],
- isOffline: [{ required: true, message: '请选择线下项目', trigger: 'change' }],
- };
- const isShowOnline = ref<boolean>(false);
- const isShowDelivery = ref<boolean>(false);
- const supplierArr = ref<any[]>([]);
- // 获取所有的供应商
- async function getSupplier(params: any) {
- supplierOptions.value = [];
- const res = await getAllSupplierMethod(params);
- if (res && res.length > 0) {
- supplierArr.value = res;
- supplierOptions.value = res.map((item: any) => ({
- label: item.name,
- value: item.id,
- }));
- getisOffline(params.conditioningProgramSupplierId, params.isOffline, params.isDelivery, params.conditioningProgramTypes);
- }
- }
- function getisOffline(e: any, newOffline: any, newDelivery: any, newType: any) {
- let filterSupplierArr = supplierArr.value.filter((item: any) => item.id === e);
- if (filterSupplierArr.length > 0) {
- isShowOnline.value = filterSupplierArr.every((items: any) => {
- if (newType.length > 0) {
- if (items.offlineCPTypes?.includes(newType[0]) && items.onlineCPTypes?.includes(newType[0])) {
- return true;
- } else {
- if (items.offlineCPTypes?.includes(newType[0])) {
- form.isOffline = 'Y';
- return false;
- } else if (items.onlineCPTypes?.includes(newType[0])) {
- form.isOffline = 'N';
- return false;
- } else {
- form.isOffline = null;
- return false;
- }
- }
- } else {
- return false;
- }
- });
- if (isShowOnline.value) {
- if (newOffline) {
- onlineArr.value = [newOffline];
- if (onlineArr.value.length > 1) {
- onlineArr.value = [onlineArr.value[onlineArr.value.length - 1]];
- } else if (onlineArr.value.length === 0) {
- onlineArr.value = [];
- }
- // newOffline ==Y 线下项目 不需要配送
- if (newOffline === 'Y') {
- form.isDelivery = null;
- isShowDelivery.value = false;
- } else {
- isShowDelivery.value = true;
- }
- } else {
- isShowDelivery.value = false;
- }
- if (newDelivery) {
- deliverArr.value = [newDelivery];
- if (deliverArr.value.length > 1) {
- deliverArr.value = [deliverArr.value[deliverArr.value.length - 1]];
- } else if (deliverArr.value.length === 0) {
- deliverArr.value = [];
- }
- }
- }
- } else {
- isShowOnline.value = false;
- isShowDelivery.value = false;
- onlineArr.value = [];
- deliverArr.value = [];
- }
- }
- watch(
- [() => form.conditioningProgramType, () => form.institutionId, () => form.conditioningProgramSupplierId, () => form.isOffline, () => form.isDelivery],
- ([newType, newInstitutionId, newSupplierId, newOffline, newDelivery]) => {
- getSupplier({
- conditioningProgramTypes: newType ? [newType] : form.conditioningProgramType ? [form.conditioningProgramType] : [],
- institutionId: newInstitutionId ? newInstitutionId : form.institutionId ? form.institutionId : '',
- conditioningProgramSupplierId: newSupplierId ? newSupplierId : form.conditioningProgramSupplierId ? form.conditioningProgramSupplierId : '',
- isOffline: newOffline,
- isDelivery: newDelivery,
- });
- },
- { immediate: true }
- );
- function addHerb() {
- if (!form.cpMedicines) {
- form.cpMedicines = [];
- }
- form.cpMedicines.push({ name: '', dosage: '', id: '' });
- }
- function removeHerb(idx: number) {
- if (form.cpMedicines) {
- form.cpMedicines.splice(idx, 1);
- }
- }
- function cancel() {
- VxeUI.modal.close(`add-items-modal`);
- }
- function doSubmit() {
- console.log(formRef.value, 'formRef==>');
- console.log(form, 'Form Data Before Submit');
- formRef.value
- ?.validate()
- .then(() => {
- form.photo = fileList.value[0]?.response?.url || fileList.value[0]?.url || '';
- submit(form);
- })
- .catch((error) => {
- console.error('Validation Error:', error);
- message.error('请完善必填项');
- });
- }
- // 获取方案类型
- async function getConditioningProgramType() {
- typeOptionsLoading.value = true;
- try {
- const res = await getDictionaryMethod('condition_type');
- if (res?.length > 0) {
- typeOptions.value = res; // 直接使用返回的数据
- }
- } catch (error) {
- console.error('获取方案类型列表失败:', error);
- } finally {
- typeOptionsLoading.value = false;
- }
- }
- onMounted(async () => {
- const deptId = localStorage.getItem('deptId');
- if (props.data.addType === 'system' && deptId) {
- form.institutionId = deptId;
- }
- if (props.data.addType === 'system') {
- isRequired.value = false;
- }
- form.addType = props.data.addType;
- if (props.data.id) {
- const res: any = await getConditioningSchemeDetailMethod(props.data);
- Object.assign(form, res);
- form.cpMedicines = (res.cpMedicines ?? []).map((item: any) => ({
- name: item.name || item.herbName || item.medicineName || '',
- dosage: item.dosage,
- id: item.id,
- }));
- fileList.value = res.photo
- ? [
- {
- uid: '-1',
- name: 'image.png',
- status: 'done',
- url: res.photo,
- thumbUrl: res.photo,
- },
- ]
- : [];
- }
- // 获取供应商
- // getSupplier({});
- // 获取方案类型
- getConditioningProgramType();
- });
- const emits = defineEmits<{
- submit: [data?: SystemItemModel];
- addSubmit: [data?: SystemItemModel];
- }>();
- const { loading: submitting, send: submit } = useRequest(systemCpEditMethod, {
- immediate: false,
- }).onSuccess(({ data }) => {
- emits('submit');
- });
- const visible = ref<boolean>(false);
- const setVisible = (value): void => {
- visible.value = value;
- };
- const previewImg = ref<string>('');
- const uploadProps = reactive({ showRemoveIcon: true });
- const fileList = ref<UploadFile[]>([]);
- // 预览图片
- const handlePreview = async (file: UploadFile) => {
- previewImg.value = file.response?.url ?? file.thumbUrl;
- visible.value = true;
- };
- function customUpload(e: any) {
- // uploadApi 你的二次封装上传接口
- UploadIFile(e.file)
- .then((res) => {
- // 调用实例的成功方法通知组件该文件上传成功
- e.onSuccess(res, e);
- })
- .catch((err) => {
- // 调用实例的失败方法通知组件该文件上传失败
- e.onError(err);
- });
- }
- watch(
- () => form.pricingType,
- (val) => {
- if (val === '0' && !form.cpFixedPricingRule) {
- form.cpFixedPricingRule = {
- unitPrice: 0,
- pricingUnit: '',
- convertDose: 0,
- convertUnit: '',
- };
- } else {
- form.cpFixedPricingRule = null;
- }
- }
- );
- function bindchange(e: any) {
- form.conditioningProgramSupplierId = '';
- form.isOffline = null;
- }
- function onlineChange(value: any) {
- form.isOffline = value[value.length - 1];
- deliverArr.value = [];
- form.isDelivery = null;
- }
- function deliveryChange(value: any) {
- form.isDelivery = value[value.length - 1];
- }
- function getConditioningProgramSupplier(value: any) {
- onlineArr.value = [];
- deliverArr.value = [];
- form.isOffline = null;
- form.isDelivery = null;
- isShowDelivery.value = false;
- }
- function handleSelect(value: string, node: any, extra: any) {
- form.institutionId = value;
- form.institutionName = node.label;
- }
- </script>
- <template>
- <div class="form-container">
- <a-form ref="formRef" :model="form" :rules="rules" layout="horizontal">
- <a-form-item label="项目名称:" name="name" required>
- <a-input v-model:value="form.name" placeholder="请输入" />
- </a-form-item>
- <a-form-item label="方案类型:" name="conditioningProgramType" required>
- <a-select
- v-model:value="form.conditioningProgramType"
- :options="typeOptions"
- placeholder="请选择"
- allowClear
- :loading="typeOptionsLoading"
- :disabled="typeOptions.length === 0"
- @change="bindchange"
- />
- </a-form-item>
- <a-form-item label="计价规则:" name="pricingType" required>
- <a-radio-group v-model:value="form.pricingType">
- <a-radio value="0">一口价</a-radio>
- <a-radio value="1">按穴位/经络/部位</a-radio>
- </a-radio-group>
- </a-form-item>
- <div class="price-row" v-if="form.pricingType === '0' && form.cpFixedPricingRule">
- <span class="label">单价:</span>
- <a-input v-model:value="form.cpFixedPricingRule.unitPrice" placeholder="请输入" style="width: 100px" />
- <span style="margin: 0 8px">元</span>
- <span class="label" style="margin-left: 32px">计价单位:</span>
- <a-input v-model:value="form.cpFixedPricingRule.pricingUnit" placeholder="请输入" style="width: 100px" />
- <span style="margin-left: 32px">相当于</span>
- <a-input v-model:value="form.cpFixedPricingRule.convertDose" placeholder="请输入" style="width: 100px; margin-left: 8px" />
- <a-select v-model:value="form.cpFixedPricingRule.convertUnit" style="width: 100px; margin-left: 8px" :options="unitOptions" placeholder="请选择" />
- <span style="color: #aaa; margin-left: 8px">(使用单位)</span>
- </div>
- <div v-if="form.pricingType === '1'" class="per-rule">
- <div class="price-row">
- <span>计价1:</span>
- <span class="flex items-center"
- >当"穴位/经络/部位" ≤
- <a-input
- placeholder="请输入"
- class="w-20 ml-2 mr-2"
- v-model:value="form.cpDynamicPricingRule[0].min"
- @change="() => (form.cpDynamicPricingRule[1].max = form.cpDynamicPricingRule[0].min)"
- />个时,</span
- >
- <a-select
- v-model:value="form.cpDynamicPricingRule[0].priceType"
- :options="[
- { label: '单价', value: 0, priceType: 0 },
- { label: '一口价', value: 1, priceType: 1 },
- ]"
- style="width: 100px; margin: 0 4px"
- placeholder="请选择"
- />
- <span>=</span>
- <a-input v-model:value="form.cpDynamicPricingRule[0].price" style="width: 80px; margin: 0 4px" placeholder="请输入" />
- <span>元</span>
- </div>
- <div class="price-row">
- <span>计价2:</span>
- <span class="flex items-center"
- >当"穴位/经络/部位" > <a-input placeholder="请输入" class="w-20 ml-2 mr-2" v-model:value="form.cpDynamicPricingRule[1].max" disabled />个时,</span
- >
- <a-select
- v-model:value="form.cpDynamicPricingRule[1].priceType"
- :options="[
- { label: '单价', value: 0, priceType: 0 },
- { label: '一口价', value: 1, priceType: 1 },
- ]"
- style="width: 100px; margin: 0 4px"
- placeholder="请选择"
- />
- <span>=</span>
- <a-input v-model:value="form.cpDynamicPricingRule[1].price" style="width: 80px; margin: 0 4px" placeholder="请输入" />
- <span>元</span>
- </div>
- </div>
- <a-form-item label="中药组成:">
- <div class="herb-list">
- <template v-for="(herb, idx) in form.cpMedicines" :key="herb.id">
- <div class="herb-item">
- <button class="herb-remove" v-if="form?.cpMedicines?.length > 1" @click="removeHerb(idx)" type="button">×</button>
- <RemoteSelect :load="cpMedicinesMethod" key-prop="name" v-model:value="herb.name" />
- <a-input v-model:value="herb.dosage" class="herb-dosage" placeholder="剂量" />
- <span>g</span>
- </div>
- </template>
- <button style="margin-left: 8px" @click="addHerb" type="button">+</button>
- </div>
- </a-form-item>
- <a-form-item label="功效:">
- <a-input v-model:value="form.effect" placeholder="请输入" />
- </a-form-item>
- <!-- 机构名称 -->
- <a-form-item label="机构名称:" v-if="form?.addType === 'itemsList'" required name="institutionId">
- <a-tree-select
- v-model:value="form.institutionId"
- style="width: 100%"
- :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
- placeholder="请选择"
- allow-clear
- tree-default-expand-all
- :tree-data="branch"
- @select="handleSelect"
- ></a-tree-select>
- </a-form-item>
- <a-form-item label="供应商:" name="conditioningProgramSupplierId" required>
- <a-select v-model:value="form.conditioningProgramSupplierId" :options="supplierOptions" placeholder="请选择" allowClear @change="getConditioningProgramSupplier" />
- </a-form-item>
- <a-form-item label="线下项目:" name="isOffline" v-if="isShowOnline" required>
- <a-checkbox-group v-model:value="onlineArr" @change="onlineChange">
- <a-checkbox value="Y">是</a-checkbox>
- <a-checkbox value="N">否</a-checkbox>
- </a-checkbox-group>
- </a-form-item>
- <a-form-item label="配送:" name="isDelivery" v-if="isShowDelivery">
- <a-checkbox-group v-model:value="deliverArr" @change="deliveryChange">
- <a-checkbox value="Y">支持</a-checkbox>
- <a-checkbox value="N">不支持</a-checkbox>
- </a-checkbox-group>
- </a-form-item>
- <a-form-item label="图片:">
- <a-upload :showUploadList="uploadProps" v-model:file-list="fileList" list-type="picture-card" @preview="handlePreview" :maxCount="1" :customRequest="customUpload">
- <div v-if="fileList.length < 1">
- <PlusOutlined />
- <div style="margin-top: 8px">上传</div>
- </div>
- </a-upload>
- </a-form-item>
- <a-image
- :width="200"
- :style="{ display: 'none' }"
- :preview="{
- visible,
- onVisibleChange: setVisible,
- }"
- :src="previewImg"
- />
- <div class="form-actions-center">
- <a-button @click="cancel">取消</a-button>
- <a-button type="primary" style="background: #faad14; border: none" @click="doSubmit">确定</a-button>
- </div>
- </a-form>
- </div>
- </template>
- <style scoped>
- .form-container {
- width: 760px;
- margin: 0 auto;
- padding: 10px 0px 0 0;
- }
- .per-rule {
- margin-bottom: 16px;
- }
- .price-row {
- display: flex;
- align-items: center;
- margin-bottom: 10px;
- }
- .label {
- font-weight: 500;
- color: #222;
- margin-right: 8px;
- }
- .herb-list {
- display: flex;
- align-items: center;
- flex-wrap: wrap;
- }
- .herb-item {
- position: relative;
- display: flex;
- align-items: center;
- margin-right: 8px;
- margin-bottom: 8px;
- padding-left: 16px;
- }
- .herb-dosage {
- width: 70px;
- padding: 2px 6px;
- font-size: 14px;
- margin-right: 10px;
- }
- .herb-remove {
- position: absolute;
- left: 0;
- top: 0;
- background: #fff;
- border: none;
- color: #ff4d4f;
- font-size: 14px;
- cursor: pointer;
- line-height: 1;
- width: 16px;
- height: 16px;
- padding: 0;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .form-actions-center {
- display: flex;
- justify-content: center;
- gap: 16px;
- /* margin-top: 32px; */
- }
- .slider-section {
- margin-bottom: 16px;
- }
- .slider-labels {
- display: flex;
- justify-content: space-between;
- width: 200px;
- margin-left: 230px;
- margin-bottom: 4px;
- font-weight: 500;
- color: #222;
- }
- .slider-row {
- display: flex;
- align-items: center;
- }
- .slider-desc {
- color: #222;
- white-space: nowrap;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- }
- .slider-value {
- margin-left: 16px;
- color: #faad14;
- font-weight: bold;
- }
- </style>
|