Browse Source

改价/分班

学习?学个屁 1 ngày trước cách đây
mục cha
commit
761795b4b1

+ 2 - 2
.env

@@ -2,10 +2,10 @@
 VITE_PORT = 3100
 
 #  网站标题
-VITE_GLOB_APP_TITLE = 中数未来
+VITE_GLOB_APP_TITLE = 全能动能
 
 # 简称,此变量只能是字符/下划线
-VITE_GLOB_APP_SHORT_NAME = zhongshuweilai
+VITE_GLOB_APP_SHORT_NAME = 全能动能
 
 # 单点登录服务端地址
 VITE_GLOB_APP_CAS_BASE_URL=http://cas.test.com:8443/cas

+ 1 - 0
src/views/businessManagement/courses/courses.data.ts

@@ -167,6 +167,7 @@ export const formSchema: FormSchema[] = [
       api: getCoachList,
       labelField: 'name',
       valueField: 'userId',
+      mode: 'multiple',
       params: { orgCode: useUserStore().userInfo?.orgCode },
     },
   },

+ 83 - 0
src/views/calssGroup/calssGroupInfo/NmClassGrouping.api.ts

@@ -0,0 +1,83 @@
+import { defHttp } from '/src/utils/http/axios';
+import { useMessage } from '/src/hooks/web/useMessage';
+
+const { createConfirm } = useMessage();
+
+enum Api {
+  list = '/app/classGrouping/queryPage',
+  caseList = '/app/classGrouping/queryCasePage',
+  studentInfoList = '/app/classGrouping/getStudentInfoList',
+  siteList = '/app/classGrouping/getSiteList',
+  queryCoach = '/app/classGrouping/getCoachInfoVOList',
+  addClass = '/app/classGrouping/add',
+  editClass = '/app/classGrouping/edit',
+  deleteClass = '/app/classGrouping/delete',
+  deleteOne = '/calssGroup/nmClassGrouping/delete',
+  deleteBatch = '/calssGroup/nmClassGrouping/deleteBatch',
+  importExcel = '/calssGroup/nmClassGrouping/importExcel',
+  exportXls = '/calssGroup/nmClassGrouping/exportXls',
+}
+
+/**
+ * 导出api
+ * @param params
+ */
+export const getExportUrl = Api.exportXls;
+/**
+ * 导入api
+ */
+export const getImportUrl = Api.importExcel;
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) => defHttp.post({ url: Api.list, params });
+export const caseList = (params) => defHttp.post({ url: Api.caseList, params });
+export const studentInfoList = (params) => defHttp.post({ url: Api.studentInfoList, params });
+export const queryCoach = (params) => defHttp.get({ url: Api.queryCoach, params });
+export const siteList = (params) => defHttp.get({ url: Api.siteList, params });
+export const addClass = (params) => defHttp.post({ url: Api.addClass, params });
+export const editClass = (params) => defHttp.post({ url: Api.editClass, params });
+// export const deleteClass = (params) => defHttp.delete({ url: Api.deleteClass, params });
+/**
+ * 删除单个
+ */
+export const deleteOne = (params, handleSuccess) => {
+  return defHttp.delete({ url: Api.deleteClass, params }, { joinParamsToUrl: true }).then(() => {
+    handleSuccess();
+  });
+};
+/**
+ * 批量删除
+ * @param params
+ */
+export const batchDelete = (params, handleSuccess) => {
+  createConfirm({
+    iconType: 'warning',
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp
+        .delete(
+          {
+            url: Api.deleteBatch,
+            data: params,
+          },
+          { joinParamsToUrl: true }
+        )
+        .then(() => {
+          handleSuccess();
+        });
+    },
+  });
+};
+/**
+ * 保存或者更新
+ * @param params
+ */
+export const saveOrUpdate = (params, isUpdate) => {
+  let url = isUpdate ? Api.edit : Api.save;
+  return defHttp.post({ url: url, params });
+};

+ 171 - 0
src/views/calssGroup/calssGroupInfo/NmClassGrouping.data.ts

@@ -0,0 +1,171 @@
+import { BasicColumn } from '/src/components/Table';
+import { FormSchema } from '/src/components/Table';
+import { siteList } from './NmClassGrouping.api';
+import { rules } from '/src/utils/helper/validator';
+import { render } from '/src/utils/common/renderUtils';
+import { getWeekMonthQuarterYear } from '/src/utils';
+import { h } from 'vue';
+import simpleMenuTag from '@/components/SimpleMenu/src/SimpleMenuTag.vue';
+import { Tag } from 'ant-design-vue';
+//列表数据
+export const columns: BasicColumn[] = [
+  {
+    title: '课程名称',
+    align: 'center',
+    dataIndex: 'name',
+  },
+  {
+    title: '课程节数及时间',
+    align: 'center',
+    dataIndex: 'classNum',
+    customRender: ({ record }) => {
+      return h('div', {}, [h('div', {}, `${record.classNum}课时`), h('div', { class: 'text-gray' }, `${record.startTime}-${record.endTime}`)]);
+    },
+  },
+  {
+    title: '上课地点',
+    align: 'center',
+    dataIndex: 'address',
+    customRender: ({ record }) => {
+      return h(Tag, { color: 'green' }, record.address);
+    },
+  },
+  {
+    title: '报名人数',
+    align: 'center',
+    dataIndex: 'applyNum',
+  },
+  {
+    title: '已分班人数',
+    align: 'center',
+    dataIndex: 'alreadyClassGroupingNum',
+  },
+  {
+    title: '未分班人数',
+    align: 'center',
+    dataIndex: 'unClassGroupingNum',
+  },
+  {
+    title: '创建时间',
+    align: 'center',
+    dataIndex: 'createTime',
+  },
+];
+
+//分班列表数据
+export const columns1: BasicColumn[] = [
+  {
+    title: '班级名称',
+    align: 'center',
+    dataIndex: 'classGroupingName',
+  },
+  {
+    title: '教练',
+    align: 'center',
+    dataIndex: 'coachName',
+  },
+  {
+    title: '学员数',
+    align: 'center',
+    dataIndex: 'applyNum',
+  },
+  {
+    title: '创建时间',
+    align: 'center',
+    dataIndex: 'createTime',
+  },
+];
+
+//待分班列表数据
+export const columns2: BasicColumn[] = [
+  {
+    title: '学员姓名',
+    align: 'center',
+    dataIndex: 'name',
+  },
+  {
+    title: '性别',
+    align: 'center',
+    dataIndex: 'gender',
+  },
+  {
+    title: '年龄',
+    align: 'center',
+    dataIndex: 'age',
+  },
+  {
+    title: '学校',
+    align: 'center',
+    dataIndex: 'schoolName',
+  },
+  {
+    title: '年级+班级',
+    align: 'center',
+    dataIndex: 'levelInfo',
+  },
+];
+
+//查询数据
+export const searchFormSchema: FormSchema[] = [
+  {
+    label: '课程名称',
+    field: 'courseName',
+    component: 'Input',
+  },
+  {
+    label: '上课地点',
+    field: 'addressSiteId',
+    component: 'ApiSelect',
+    componentProps: {
+      api: siteList,
+      labelField: 'siteName',
+      valueField: 'siteId',
+    },
+  },
+];
+
+export const searchFormSchemaModal: FormSchema[] = [
+  {
+    label: '班级名称',
+    field: 'classGroupingName',
+    component: 'Input',
+    colProps: { span: 8 },
+  },
+];
+//表单数据
+export const formSchema: FormSchema[] = [
+  {
+    label: '班级名称',
+    field: 'className',
+    component: 'Input',
+    colProps: { span: 8 },
+  },
+  {
+    label: '教练',
+    field: 'courseId',
+    component: 'Select',
+    colProps: { span: 8 },
+  },
+  {
+    label: '待分班学员',
+    field: 'courseId',
+    component: 'BasicTable',
+  },
+];
+
+// 高级查询数据
+export const superQuerySchema = {
+  className: { title: '班级名称', order: 0, view: 'text', type: 'string' },
+  courseId: { title: '课程ID', order: 1, view: 'text', type: 'string' },
+  coachUserId: { title: '用户ID(教练)', order: 2, view: 'text', type: 'string' },
+  status: { title: '系统状态(0-正常,1-冻结)', order: 3, view: 'number', type: 'number' },
+};
+
+/**
+ * 流程表单调用这个方法获取formSchema
+ * @param param
+ */
+export function getBpmFormSchema(_formData): FormSchema[] {
+  // 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
+  return formSchema;
+}

+ 116 - 0
src/views/calssGroup/calssGroupInfo/NmClassGroupingList.vue

@@ -0,0 +1,116 @@
+<template>
+  <div>
+    <!--引用表格-->
+    <BasicTable @register="registerTable">
+      <!--插槽:table标题-->
+      <template #tableTitle>
+      </template>
+      <!--操作栏-->
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)" />
+      </template>
+      <!--字段回显插槽-->
+      <template v-slot:bodyCell="{ column, record, index, text }"> </template>
+    </BasicTable>
+    <!-- 表单区域 -->
+    <NmClassGroupingModal @register="registerModal" @success="handleSuccess"></NmClassGroupingModal>
+  </div>
+</template>
+
+<script lang="ts" name="calssGroup-nmClassGrouping" setup>
+  import { ref, reactive, computed, unref } from 'vue';
+  import { BasicTable, useTable, TableAction } from '/src/components/Table';
+  import { useModal } from '/src/components/Modal';
+  import { useListPage } from '/src/hooks/system/useListPage';
+  import NmClassGroupingModal from './components/NmClassGroupingModal.vue';
+  import { columns, searchFormSchema, superQuerySchema } from './NmClassGrouping.data';
+  import { list, siteList, batchDelete, getImportUrl, getExportUrl } from './NmClassGrouping.api';
+  import { useUserStore } from '/src/store/modules/user';
+  import { useMessage } from '/src/hooks/web/useMessage';
+
+  const queryParam = reactive<any>({});
+  const checkedKeys = ref<Array<string | number>>([]);
+  const userStore = useUserStore();
+  const { createMessage } = useMessage();
+  //注册model
+  const [registerModal, { openModal }] = useModal();
+  //注册table数据
+  const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
+    tableProps: {
+      title: 'nm_class_grouping',
+      api: list,
+      columns,
+      canResize: false,
+      formConfig: {
+        //labelWidth: 120,
+        schemas: searchFormSchema,
+        autoSubmitOnEnter: true,
+        showAdvancedButton: true,
+        fieldMapToNumber: [],
+        fieldMapToTime: [],
+      },
+      actionColumn: {
+        width: 120,
+        fixed: 'right',
+      },
+      beforeFetch: (params) => {
+        return Object.assign(params, queryParam);
+      },
+    },
+    exportConfig: {
+      name: 'nm_class_grouping',
+      url: getExportUrl,
+      params: queryParam,
+    },
+    importConfig: {
+      url: getImportUrl,
+      success: handleSuccess,
+    },
+  });
+
+  const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
+
+  /**
+   * 编辑事件
+   */
+  function handleEdit(record: Recordable) {
+    openModal(true, {
+      record,
+      isUpdate: true,
+      showFooter: true,
+    });
+  }
+
+  /**
+   * 批量删除事件
+   */
+  async function batchHandleDelete() {
+    await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
+  }
+
+  /**
+   * 成功回调
+   */
+  function handleSuccess() {
+    (selectedRowKeys.value = []) && reload();
+  }
+
+  /**
+   * 操作栏
+   */
+  function getTableAction(record) {
+    return [
+      {
+        label: '分班列表',
+        onClick: handleEdit.bind(null, record),
+      },
+    ];
+  }
+</script>
+
+<style lang="less" scoped>
+  :deep(.ant-picker),
+  :deep(.ant-input-number) {
+    width: 100%;
+  }
+</style>

+ 110 - 4
src/views/orderManagement/order/index.vue

@@ -76,18 +76,56 @@
   <a-modal v-model:open="orderRefund" title="发起退款" @ok="handleRefund" :confirmLoading="RefundLoading">
     <BasicForm :showActionButtonGroup="false" @register="refundFrom" required style="margin: 50px 50px 0 50px" />
   </a-modal>
+  <a-modal v-model:open="orderPriceEdit" title="价格修改" width="80%" @ok="handleOrderPriceEdit" :confirmLoading="PriceEditLoading">
+    <BasicTable
+      title="订单信息"
+      @register="registerTableEdit"
+      @edit-end="handleEditEnd"
+      @edit-cancel="handleEditCancel"
+      :beforeEditSubmit="beforeEditSubmit"
+    />
+    <Divider></Divider>
+    <div class="pa4">
+      <TypographyTitle :level="5">费用信息</TypographyTitle>
+      <div class="mt3 border border-solid pa3 rounded-md">
+        <div class="flex items-center justify-between font-semibold">
+          <div>费用类型</div>
+          <div>金额/元</div>
+        </div>
+        <Divider></Divider>
+        <div class="flex items-center justify-between">
+          <div>商品总额</div>
+          <div v-if="editOrderInfo && editOrderInfo.orderProInfoList && editOrderInfo.orderProInfoList.length > 0">
+            <a-tag color="purple">{{ editOrderInfo?.orderProInfoList[0].originalPrice }}</a-tag>
+          </div>
+        </div>
+        <div class="flex items-center justify-between pt2">
+          <div>团购优惠</div>
+          <div v-if="editOrderInfo && editOrderInfo.orderProInfoList && editOrderInfo.orderProInfoList.length > 0">
+            <a-tag color="green">-{{ editOrderInfo?.orderProInfoList[0].originalPrice - editOrderInfo?.orderProInfoList[0].price }} </a-tag>
+          </div>
+        </div>
+      </div>
+      <div class="mt3"></div>
+      <a-descriptions bordered>
+        <a-descriptions-item label="需付款">
+          <a-tag color="orange">{{ calculateTotalPrice() }}</a-tag>
+        </a-descriptions-item>
+      </a-descriptions>
+    </div>
+  </a-modal>
 </template>
 
 <script setup lang="ts">
   import orderModelView from './components/orderModelView.vue';
-  import { Image, message, Modal, QRCode } from 'ant-design-vue';
-  import { ref, reactive, computed, unref } from 'vue';
+  import { Divider, Image, message, Modal, QRCode, TypographyTitle } from 'ant-design-vue';
+  import { ref, reactive, computed, nextTick } from 'vue';
   import { BasicTable, TableAction } from '/@/components/Table';
   import { useForm, BasicForm, FormSchema } from '/@/components/Form';
   import { useModal } from '/@/components/Modal';
   import { useListPage } from '/@/hooks/system/useListPage';
-  import { columns, searchFormSchema, afterSaleStatus, orderStatus } from './order.data';
-  import { list, exportData, queryEvents, queryProject, putProfitSharing, putQueryProfitSharing, submitOrderRefund } from './order.api';
+  import { columns, searchFormSchema, afterSaleStatus, orderStatus, editColumns } from './order.data';
+  import { list, exportData, queryEvents, queryProject, putProfitSharing, putQueryProfitSharing, submitOrderRefund, changeOrder } from './order.api';
   import { useUserStore } from '/@/store/modules/user';
   import { useMessage } from '/@/hooks/web/useMessage';
 
@@ -120,6 +158,17 @@
   });
 
   const [registerTable, { reload }, { selectedRowKeys }] = tableContext;
+
+  // 编辑价格表格注册
+  const { tableContext: editTableContext } = useListPage({
+    tableProps: {
+      // api: '',
+      columns: editColumns,
+      pagination: false,
+      actionColumn: null,
+    },
+  });
+  const [registerTableEdit, { reload: reloadEdit, setProps }] = editTableContext;
   //自定义表单字段
   const formSchemas: FormSchema[] = [
     {
@@ -190,6 +239,49 @@
     actionColOptions: { span: 17 },
   });
 
+  function calculateTotalPrice() {
+    if (!editOrderInfo.value || !editOrderInfo.value.orderProInfoList) {
+      return 0;
+    }
+    return editOrderInfo.value.orderProInfoList
+      .reduce((total, item) => {
+        const price = item.modifiedPrice !== undefined ? item.modifiedPrice : '0.00';
+        return total + parseFloat(price || 0);
+      }, 0)
+      .toFixed(2);
+  }
+
+  // 改价1提交
+  const PriceEditLoading = ref(false);
+  const totalPrice = ref(0);
+
+  async function handleOrderPriceEdit() {
+    try {
+      PriceEditLoading.value = true;
+      // 组织请求参数
+      const orderItemList = editOrderInfo.value.orderProInfoList.map((item) => ({
+        productId: item.productId,
+        originalPrice: item.modifiedPrice !== undefined ? item.modifiedPrice : item.originalPrice,
+      }));
+      // 计算总价
+      totalPrice.value = orderItemList.reduce((sum, item) => sum + parseFloat(item.originalPrice || 0), 0).toFixed(2);
+      const params = {
+        orderId: editOrderInfo.value.id,
+        price: totalPrice.value,
+        orderItemList: orderItemList,
+      };
+      await changeOrder(params);
+      message.success('价格修改成功');
+      orderPriceEdit.value = false;
+      reload();
+    } catch (error) {
+      console.error('价格修改失败:', error);
+      // message.error('价格修改失败,请稍后重试');
+    } finally {
+      PriceEditLoading.value = false;
+    }
+  }
+
   /**
    * 编辑事件
    */
@@ -251,6 +343,9 @@
     }
   }
 
+  const orderPriceEdit = ref(false);
+  const editOrderInfo = ref({});
+
   /**
    * 操作栏
    */
@@ -280,6 +375,17 @@
         onClick: submitRefund.bind(null, record),
         ifShow: (record.orderType == 3 || record.orderType == 4) && (record.orderStatus == 1 || record.orderStatus == 2),
       },
+      {
+        label: '改价',
+        ifShow: record.orderStatus==0,
+        onClick: async () => {
+          console.log(record, '选中数据');
+          orderPriceEdit.value = true;
+          await nextTick();
+          editOrderInfo.value = record;
+          setProps({ dataSource: record.orderProInfoList });
+        },
+      },
     ];
   }
 

+ 3 - 1
src/views/orderManagement/order/order.api.ts

@@ -8,7 +8,8 @@ enum Api {
   exportData = '/app/appOrder/exportCondition',
   profitSharing = '/app/appOrder/profitSharing',
   queryProfitSharing = '/app/appOrder/profitSharingReflush',
-  refund='/app/order/gameRefundOrder'
+  refund='/app/order/gameRefundOrder',
+  changeOrder='/app/appOrder/priceChange'
 }
 
 /**
@@ -20,6 +21,7 @@ export const submitOrderRefund = (params) => defHttp.get({ url: Api.refund, para
 export const queryByid = (orderId) => defHttp.get<AppOrderInfoVO>({ url: `${Api.queryByid}/${orderId}` });
 export const queryEvents = (params) => defHttp.get({ url: Api.queryEvents, params });
 export const queryProject = (params) => defHttp.get({ url: Api.queryProject, params });
+export const changeOrder = (params) => defHttp.post({ url: Api.changeOrder, params });
 export const putProfitSharing = (params) => {
   const queryString = new URLSearchParams(params).toString();
   return defHttp.put({ url: `${Api.profitSharing}?${queryString}` });

+ 45 - 0
src/views/orderManagement/order/order.data.ts

@@ -57,6 +57,51 @@ export const columns: BasicColumn[] = [
     },
   },
 ];
+
+export const editColumns: BasicColumn[] = [
+  {
+    title: '商品名称',
+    align: 'left',
+    dataIndex: 'productName',
+  },
+  {
+    title: '原价/元',
+    align: 'left',
+    dataIndex: 'originalPrice',
+  },
+  {
+    title: '销售价/元',
+    align: 'left',
+    dataIndex: 'price',
+  },
+  {
+    title: '修改销售价/元',
+    align: 'left',
+    dataIndex: 'modifiedPrice', // 使用不同的字段名
+    editComponent: 'InputNumber',
+    edit: true,
+    editRule: async (text, record) => {
+      if (text > record.originalPrice) {
+        return '不能高于原价';
+      }
+      record.modifiedPrice = text; // 更新修改后的价格字段
+      return '';
+    },
+  },
+  {
+    title: '数量',
+    align: 'left',
+    dataIndex: '',
+    customRender: () => {
+      return 1;
+    },
+  },
+  {
+    title: '小计/元',
+    align: 'left',
+    dataIndex: 'originalPrice',
+  },
+];
 //查询数据
 export const searchFormSchema: FormSchema[] = [
   {