Эх сурвалжийг харах

Merge branch 'story-238' of ssh://121.43.162.141:10022/six.fe/health.admin into feature/test

张田田 1 сар өмнө
parent
commit
7e79798b87

BIN
src/assets/images/cancel.png


+ 16 - 0
src/model/order.model.ts

@@ -161,4 +161,20 @@ export interface EvaluateDetailModel {
   depict: string;//	评价描述
   imageVideos: string[];//图片视频
   createTime: string;//创建时间
+}
+
+export interface ApplyRecordModel{
+  id: number; // 主键ID
+  arrangeTime: string; // 预定时间
+  arrangeDuration: number; // 预定时长
+  arrangePeriod: string; // 服务时间段
+  applyTime: string; // 预约时间
+  updateTime: string; // 更新预约时间
+  cancelTime: string; // 取消预约时间
+  conditioningProgramSupplierId: number; // 供应商ID
+  conditioningProgramSupplierName: string; // 供应商名称
+  pieBy: string; // 派单人
+  pieTime: string; // 派单时间
+  operateTime: string; // 操作时间
+  status: string; // 服务状态
 }

+ 7 - 2
src/order/DispatchOrderPanel.vue

@@ -133,7 +133,10 @@ function calculateEndTime(order: OrderModel): string | null {
 function isOrderVerified(order: OrderModel): boolean {
   return props.orderType === 'offline' && order.type === 3;
 }
-
+// 判断订单是否取消预约派单(线下服务)
+function isOrderCancelPie(order: OrderModel): boolean {
+  return props.orderType === 'offline' && order.type === 4;
+}
 // 判断订单是否已发货(实体商品)
 function isOrderShipped(order: OrderModel): boolean {
   return props.orderType === 'physical' && order.type === 3;
@@ -1101,9 +1104,11 @@ defineExpose({
                 <!-- 已核销/已发货印章 -->
                 <!-- 线下服务:已核销状态显示已核销图标 -->
                 <!-- 实体商品:已发货状态显示已发货图标 -->
-                <div v-if="isOrderVerified(order) || isOrderShipped(order)" class="verified-badge">
+                <div v-if="isOrderVerified(order) || isOrderShipped(order) || isOrderCancelPie(order)" class="verified-badge">
                   <img v-if="isOrderVerified(order)" src="@/assets/images/verify.png" alt="已核销"
                     style="width: 100px; height: 100px;" />
+                  <img v-else-if="isOrderCancelPie(order)" src="@/assets/images/cancel.png" alt="已取消派单"
+                    style="width: 100px; height: 100px;" />
                   <img v-else-if="isOrderShipped(order)" src="@/assets/images/shipment.png" alt="已发货"
                     style="width: 100px; height: 100px;" />
                 </div>

+ 48 - 29
src/pages/index/system/institution.vue

@@ -1,30 +1,45 @@
 <script setup lang="ts">
 import InstitutionEdit from '@/components/InstitutionEdit.vue';
-import UserPassword from '@/components/UserPassword.vue';
-import UserPreview from '@/components/UserPreview.vue';
-import UserQRCode from '@/components/UserQRCode.vue';
 import { type InstitutionModel, type InstitutionQuery } from '@/model/system.model';
 
-import { branchMethod, institutionMethod, editInstitutionMethod, deleteInstitutionMethod } from '@/request/api/system.api';
+import { branchMethod, institutionMethod, deleteInstitutionMethod } from '@/request/api/system.api';
 import { usePagination, useRequest } from 'alova/client';
 import { notification } from 'ant-design-vue';
 
 import { VxeButton, type VxeFormListeners, type VxeFormProps, type VxeGridInstance, type VxeGridListeners, type VxeGridProps, VxeUI } from 'vxe-pc-ui';
 
-const { data: branch, loading: branchLoading } = useRequest(branchMethod);
-const organizationOptions = ref<{ label: string; value: string }[]>([
-  { label: 'liuzhi', value: '1' },
-  { label: 'alice', value: '2' },
-]);
+const { data: branch, loading: branchLoading } = useRequest(branchMethod(0, 1, 1));
 const model = shallowRef<InstitutionQuery>();
+function findDeptLabelById(id: any, nodes?: any[]): string | undefined {
+  if (!id || !Array.isArray(nodes)) return;
+  const target = String(id);
+  for (const n of nodes) {
+    if (n?.id !== undefined && String(n.id) === target) return n?.label;
+    const hit = findDeptLabelById(id, n?.children);
+    if (hit) return hit;
+  }
+}
 const searchFormProps = reactive<VxeFormProps<InstitutionQuery>>({
   titleWidth: 100,
   titleAlign: 'right',
   titleColon: true,
   data: {},
   items: [
-    { field: 'userName', title: '组织名称', span: 8, itemRender: { name: 'VxeSelect', props: { options: organizationOptions, optionProps: { value: 'value', label: 'label' } } } },
-    { field: 'nickName', title: '机构名称', span: 8, itemRender: { name: 'VxeInput' } },
+    {
+      field: 'orgName',
+      title: '组织名称',
+      span: 8,
+      itemRender: {
+        name: 'VxeTreeSelect',
+        props: {
+          loading: computed(() => branchLoading.value),
+          options: computed(() => branch.value),
+          optionProps: { value: 'id', label: 'label' },
+          clearable: true,
+        },
+      },
+    },
+    { field: 'name', title: '机构名称', span: 8, itemRender: { name: 'VxeInput' } },
     {
       span: 8,
       itemRender: {
@@ -39,13 +54,15 @@ const searchFormProps = reactive<VxeFormProps<InstitutionQuery>>({
 });
 const searchFormEmits: VxeFormListeners<InstitutionQuery> = {
   submit({ data }) {
-    model.value = { ...data };
+    const orgName = findDeptLabelById((data as any)?.orgName, branch.value as any) ?? (data as any)?.orgName;
+    model.value = { ...(data as any), orgName };
   },
   reset({ data }) {
     model.value = { ...data };
   },
 };
 
+const gridEvents: VxeGridListeners = {};
 const gridRef = ref<VxeGridInstance<InstitutionModel>>();
 const gridOptions = reactive<VxeGridProps<InstitutionModel>>({
   id: 'user-list',
@@ -96,7 +113,7 @@ const gridOptions = reactive<VxeGridProps<InstitutionModel>>({
           { content: '小程序码', status: 'primary', name: 'QRCode' },
         ],
         events: {
-          click({ row, rowIndex }, { name }) {
+          click({ row, rowIndex }: any, { name }: any) {
             let method;
             if (name === 'editInstitution') {
               method = editInstitution;
@@ -157,13 +174,16 @@ function editInstitution(model?: InstitutionModel, index?: number) {
     storage: true,
     slots: {
       default() {
-        return h(InstitutionEdit, <any>{
-          data: model,
-          onSubmit(data?: InstitutionModel) {
-            refresh(page.value);
-            VxeUI.modal.close(`institution-edit-modal`);
-          },
-        });
+        return h(
+          InstitutionEdit,
+          {
+            data: model,
+            onSubmit(data?: InstitutionModel) {
+              refresh(page.value);
+              VxeUI.modal.close(`institution-edit-modal`);
+            },
+          } as any
+        );
       },
     },
   });
@@ -183,9 +203,12 @@ function QRCode(model: InstitutionModel) {
     width: 256 + 12 * 2,
     slots: {
       default() {
-        return h(UserQRCode, <any>{
-          dataset: model,
-        });
+        return h(
+          UserQRCode,
+          {
+            dataset: model,
+          } as any
+        );
       },
     },
   });
@@ -207,12 +230,8 @@ function QRCode(model: InstitutionModel) {
       </vxe-grid>
     </main>
     <footer class="flex-none">
-      <vxe-pager
-        v-model:current-page="page"
-        v-model:page-size="pageSize"
-        :total="total"
-        :layouts="['Home', 'PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'End', 'Sizes', 'FullJump', 'Total']"
-      />
+      <vxe-pager v-model:current-page="page" v-model:page-size="pageSize" :total="total"
+        :layouts="['Home', 'PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'End', 'Sizes', 'FullJump', 'Total']" />
     </footer>
   </div>
 </template>

+ 48 - 29
src/pages/index/system/organization.vue

@@ -1,17 +1,23 @@
 <script setup lang="ts">
 import OrganizationManagement from '@/components/OrganizationManagement.vue';
 import type { OrganizationModel, OrganizationQuery } from '@/model/system.model';
-
 import { organizationMethod, deleteOrganizationMethod } from '@/request/api/system.api';
-import { usePagination } from 'alova/client';
+import { usePagination, useRequest } from 'alova/client';
 import { notification } from 'ant-design-vue';
 import PatientBelong from '@/components/PatientBelong.vue';
 import { type VxeFormListeners, type VxeFormProps, type VxeGridInstance, type VxeGridListeners, type VxeGridProps, VxeUI } from 'vxe-pc-ui';
-const organizationOptions = ref<{ label: string; value: string }[]>([
-  { label: 'liuzhi', value: '1' },
-  { label: 'alice', value: '2' },
-]);
+import { branchMethod } from '@/request/api/system.api';
 const model = shallowRef<OrganizationQuery>();
+const { data: branch, loading: branchLoading } = useRequest(branchMethod(0, 1, 1));
+function findDeptLabelById(id: any, nodes?: any[]): string | undefined {
+  if (!id || !Array.isArray(nodes)) return;
+  const target = String(id);
+  for (const n of nodes) {
+    if (n?.id !== undefined && String(n.id) === target) return n?.label;
+    const hit = findDeptLabelById(id, n?.children);
+    if (hit) return hit;
+  }
+}
 const searchFormProps = reactive<VxeFormProps<OrganizationQuery>>({
   titleWidth: 100,
   titleAlign: 'right',
@@ -20,8 +26,18 @@ const searchFormProps = reactive<VxeFormProps<OrganizationQuery>>({
     name: '',
   },
   items: [
-    { field: 'name', title: '组织名称', span: 8, itemRender: { name: 'VxeSelect', props: { options: organizationOptions, optionProps: { value: 'value', label: 'label' } } } },
-
+    {
+      field: 'name', title: '组织名称', span: 8,
+      itemRender: {
+        name: 'VxeTreeSelect',
+        props: {
+          loading: computed(() => branchLoading.value),
+          options: computed(() => branch.value),
+          optionProps: { value: 'id', label: 'label' },
+          clearable: true,
+        },
+      },
+    },
     {
       span: 16,
       itemRender: {
@@ -39,7 +55,8 @@ const searchFormProps = reactive<VxeFormProps<OrganizationQuery>>({
 });
 const searchFormEmits: VxeFormListeners<OrganizationQuery> = {
   submit({ data }) {
-    model.value = { ...data };
+    const name = findDeptLabelById((data as any)?.name, branch.value as any) ?? (data as any)?.name;
+    model.value = { ...(data as any), name };
   },
   reset({ data }) {
     model.value = { ...data };
@@ -164,13 +181,16 @@ function editOrganization(model?: OrganizationModel, index?: number) {
     height: 600,
     slots: {
       default() {
-        return h(OrganizationManagement, <any>{
-          data: model,
-          onSubmit(data: OrganizationModel) {
-            refresh(page.value);
-            VxeUI.modal.close(`organization-edit-modal`);
-          },
-        });
+        return h(
+          OrganizationManagement,
+          {
+            data: model,
+            onSubmit(data: OrganizationModel) {
+              refresh(page.value);
+              VxeUI.modal.close(`organization-edit-modal`);
+            },
+          } as any
+        );
       },
     },
   });
@@ -188,13 +208,16 @@ function setPatientBelong(model: OrganizationModel, index: number) {
     height: 600,
     slots: {
       default() {
-        return h(PatientBelong, <any>{
-          data: model,
-          onSubmit(data: OrganizationModel) {
-            refresh(page.value);
-            VxeUI.modal.close(`patient-belong-modal`);
-          },
-        });
+        return h(
+          PatientBelong,
+          {
+            data: model,
+            onSubmit(data: OrganizationModel) {
+              refresh(page.value);
+              VxeUI.modal.close(`patient-belong-modal`);
+            },
+          } as any
+        );
       },
     },
   });
@@ -216,12 +239,8 @@ function setPatientBelong(model: OrganizationModel, index: number) {
       </vxe-grid>
     </main>
     <footer class="flex-none">
-      <vxe-pager
-        v-model:current-page="page"
-        v-model:page-size="pageSize"
-        :total="total"
-        :layouts="['Home', 'PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'End', 'Sizes', 'FullJump', 'Total']"
-      />
+      <vxe-pager v-model:current-page="page" v-model:page-size="pageSize" :total="total"
+        :layouts="['Home', 'PrevJump', 'PrevPage', 'Number', 'NextPage', 'NextJump', 'End', 'Sizes', 'FullJump', 'Total']" />
     </footer>
   </div>
 </template>

+ 15 - 2
src/request/api/order.api.ts

@@ -1,7 +1,9 @@
 import type { List, Tree } from '@/model';
 import type {
   OrderQuery,
-  OrderModel, OrderLiaisonListModel, ShipmentModel, ShipmentQuery, PieOrderCountModel, RevenueSharingDetailModel, RevenueSharingDetailQuery, EvaluateDetailModel
+  OrderModel, OrderLiaisonListModel, ShipmentModel, ShipmentQuery, 
+  PieOrderCountModel, RevenueSharingDetailModel, RevenueSharingDetailQuery,
+   EvaluateDetailModel, ApplyRecordModel
 } from '@/model/order.model';
 import request from '@/request/alova';
 
@@ -178,4 +180,15 @@ export function getEvaluateDetailMethod(type: string, id: string) {
       hitSource: /order$/, // 匹配失效源
     }
   );
-} 
+}
+
+// 获取线下服务的预约派单记录 	线下服务id
+export function getApplyRecordMethod(id: string) {
+  return request.Post<ApplyRecordModel[]>(
+    `/fdhb-pc/patientCrManage/getApplyRecord/${id}`,
+    {},
+    {
+      hitSource: /order$/, // 匹配失效源
+    }
+  );
+} 

+ 59 - 28
src/service/SingleItemDetail.vue

@@ -1,5 +1,6 @@
 <script setup lang="ts">
 import type { SystemCwModel } from '@/model/care.model';
+import type { ApplyRecordModel } from '@/model/order.model';
 import { PlayCircleOutlined } from '@ant-design/icons-vue';
 import { computed, h, onMounted, ref } from 'vue';
 import { notification } from 'ant-design-vue';
@@ -7,28 +8,27 @@ import VxeUI from 'vxe-table';
 import ReviewMediaPreview from '@/service/ReviewMediaPreview.vue';
 import type { MediaItem } from '@/service/ReviewMediaPreview.vue';
 import seeEvaluate from '@/service/seeEvaluate.vue';
-import { getEvaluateDetailMethod } from '@/request/api/order.api';
-
+import { getEvaluateDetailMethod, getApplyRecordMethod } from '@/request/api/order.api';
 
 const props = defineProps<{
   data: SystemCwModel['items'][number];
 }>();
 // 服务记录--查看评价
 function openSeeEvaluate(row: any) {
-    VxeUI.modal.open({
-      title: '用户评价',
-      width: 900,
-      height: 600,
-      escClosable: true,
-      destroyOnClose: true,
-      slots: {
-        default() {
-          return h(seeEvaluate, {
-            data: row,
-          });
-        },
+  VxeUI.modal.open({
+    title: '用户评价',
+    width: 900,
+    height: 600,
+    escClosable: true,
+    destroyOnClose: true,
+    slots: {
+      default() {
+        return h(seeEvaluate, {
+          data: row,
+        });
       },
-    });
+    },
+  });
 }
 // 复制物流信息
 function handleCopyTracking() {
@@ -145,7 +145,17 @@ async function getEvaluateDetail() {
   evaluateDetail.value.depict = res.depict ?? '';
   evaluateDetail.value.mediaList = normalizeMediaList(res.imageVideos);
 }
-
+const applyRecordList = ref<ApplyRecordModel[]>([]);
+// 获取预约
+async function getApplyRecord() {
+  const id = (props.data as any)?.id;
+  if (!id) return;
+  const res = await getApplyRecordMethod(id);
+  if (!res) return;
+  console.log(res, "获取预约");
+  applyRecordList.value = res ?? [];
+  console.log(applyRecordList.value, "applyRecordList");
+}
 const REVIEW_PREVIEW_MODAL_ID = 'review-media-preview-modal';
 //预览图片/视频
 function openPreview(list: MediaItem[], index: number) {
@@ -167,8 +177,9 @@ function openPreview(list: MediaItem[], index: number) {
   });
 }
 
-onMounted(() => {
-  getEvaluateDetail();
+onMounted(async () => {
+  await getEvaluateDetail();
+  await getApplyRecord();
 });
 </script>
 
@@ -236,16 +247,13 @@ onMounted(() => {
     <!-- 分账信息 -->
     <div class="info-section">
       <h3 class="info-title">分账信息</h3>
-      <vxe-table
-        class="split-account-table"
-        :data="mockSplitAccountList"
-        border
-      >
+      <vxe-table class="split-account-table" :data="mockSplitAccountList" border>
         <vxe-column field="profitSharingTime" title="分账时间" align="center" />
         <vxe-column field="conditioningProgramSupplierName" title="供应商" align="center" />
-        <vxe-column field="profitSharingStatus" title="分账状态" align="center" >
+        <vxe-column field="profitSharingStatus" title="分账状态" align="center">
           <template #default="{ row }">
-            {{ row.profitSharingStatus === '1' ? '未分账' : row.profitSharingStatus === '2' ? '已分账' : row.profitSharingStatus === '3' ? '分账异常' : '' }}
+            {{ row.profitSharingStatus === '1' ? '未分账' : row.profitSharingStatus === '2' ? '已分账' :
+              row.profitSharingStatus === '3' ? '分账异常' : '' }}
           </template>
         </vxe-column>
         <vxe-column field="profitSharing" title="分账比例" align="center">
@@ -253,7 +261,7 @@ onMounted(() => {
             {{ row.profitSharing || '-' }}%
           </template>
         </vxe-column>
-        <vxe-column field="profitSharingAmount" title="预计分账金额" align="center" >
+        <vxe-column field="profitSharingAmount" title="预计分账金额" align="center">
           <template #default="{ row }">
             {{ row.profitSharingAmount ? row.profitSharingAmount + '元' : '' }}
           </template>
@@ -327,13 +335,35 @@ onMounted(() => {
         暂无
       </div>
     </div>
-
+    <!-- 预约派单记录 线下服务才显示  1-实体商品 2-线下服务 3-线上权益-->
+    <div class="info-section" v-if="data?.sellType === '2'">
+      <h3 class="info-title">
+        预约派单记录
+      </h3>
+      <vxe-table :data="applyRecordList" border>
+        <vxe-column type="seq" title="序号" width="60" align="center" />
+        <vxe-column field="applyTime" title="预约时间" align="center" />
+        <vxe-column field="updateTime" title="最新修改预约时间" align="center" />
+        <vxe-column field="cancelTime" title="取消预约时间" align="center" />
+        <vxe-column field="arrangeTime" title="预约服务日期" align="center" />
+        <vxe-column field="arrangePeriod" title="预约服务时间段" align="center" />
+        <vxe-column field="pieTime" title="是否派单" align="center">
+          <template #default="{ row }">
+            {{ row.pieTime ? '是' : '否' }}
+          </template>
+        </vxe-column>
+        <vxe-column field="pieBy" title="派单员" align="center" />
+        <vxe-column field="pieTime" title="派单时间" align="center" />
+        <vxe-column field="conditioningProgramSupplierName" title="服务机构" align="center" />
+        <vxe-column field="status" title="服务状态" align="center" />
+      </vxe-table>
+    </div>
     <!-- 服务记录 线下服务才显示  1-实体商品 2-线下服务 3-线上权益-->
     <div class="info-section" v-if="data?.sellType === '2'">
       <h3 class="info-title">
         服务记录
         <span class="title-count">({{ data?.patientConditioningOfflines?.length || 0 }}/{{ data?.totalMeasure || 0
-        }})</span>
+          }})</span>
       </h3>
       <vxe-table :data="data?.patientConditioningOfflines" border>
         <vxe-column type="seq" title="序号" width="60" align="center" />
@@ -626,6 +656,7 @@ onMounted(() => {
 
   /* 分账表格仅按内容自适应高度,避免一行数据时出现多余空白 */
   .split-account-table {
+
     :deep(.vxe-table--wrapper),
     :deep(.vxe-table) {
       height: auto !important;