Bladeren bron

财务管理模块

学习?学个屁 1 week geleden
bovenliggende
commit
064bc0e0fb

+ 4 - 4
.env.development

@@ -7,16 +7,16 @@ VITE_PUBLIC_PATH = /
 
 
 # 跨域代理,您可以配置多个 ,请注意,没有换行符
-# VITE_PROXY = [["/jeecgboot","http://192.168.0.217:8080/jeecg-boot"],["/upload","http://192.168.0.217:8080/jeecg-boot"]]
-VITE_PROXY = [["/jeecgboot","http://192.168.0.11:8080/jeecg-boot"],["/upload","http://192.168.0.11:8080/upload"]]
+VITE_PROXY = [["/jeecgboot","http://192.168.0.217:8080/jeecg-boot"],["/upload","http://192.168.0.217:8080/jeecg-boot"]]
+# VITE_PROXY = [["/jeecgboot","http://192.168.0.11:8080/jeecg-boot"],["/upload","http://192.168.0.11:8080/upload"]]
 # VITE_PROXY = [["/jeecgboot","http://192.168.1.253:8080/jeecg-boot"],["/upload","http://192.168.1.253:8080/upload"]]
 # VITE_PROXY = [["/jeecgboot","http://192.168.1.166:8080/jeecg-boot"],["/upload","http://192.168.1.166:8080/upload"]]
 # VITE_PROXY = [["/jeecgboot","http://47.109.18.141:8080/jeecg-boot"],["/upload","http://47.109.18.141:8080/upload"]]
 # VITE_PROXY = [["/jeecgboot","https://api.qlapp.cn/jeecg-boot"],["/upload","https://api.qlapp.cn/upload"]]
 
 #后台接口全路径地址(必填)
-# VITE_GLOB_DOMAIN_URL=http://192.168.0.217:8080/jeecg-boot #//黄
-VITE_GLOB_DOMAIN_URL=http://192.168.0.11:8080/jeecg-boot  #李
+VITE_GLOB_DOMAIN_URL=http://192.168.0.217:8080/jeecg-boot #//黄
+# VITE_GLOB_DOMAIN_URL=http://192.168.0.11:8080/jeecg-boot  #李
 # VITE_GLOB_DOMAIN_URL=http://192.168.1.253:8080/jeecg-boot  #张
 # VITE_GLOB_DOMAIN_URL=http://192.168.1.166:8080/jeecg-boot  #张
 # VITE_GLOB_DOMAIN_URL=http://47.109.18.141:8080/jeecg-boot  #fwq

+ 73 - 0
src/views/Finance/balance/balance.api.ts

@@ -0,0 +1,73 @@
+import { defHttp } from '/@/utils/http/axios';
+import { useMessage } from '/@/hooks/web/useMessage';
+
+const { createConfirm } = useMessage();
+
+enum Api {
+  list = '/statisticsInfo/findShopAccountOverview',
+  save = '/app/appCourese/add',
+  edit = '/app/appCourese/edit',
+  deleteOne = '/app/appCourese/delete',
+  detaile = '/app/appCourese/queryById',
+  address = '/app/appCourese/queryAddressList',
+  Coach = '/staff/staff/queryList',
+  queryCourseList = '/app/appCoursesPriceRules/queryListByCoursesId',
+  editPriceRules = '/app/appCoursesPriceRules/editPriceRules',
+  updateStatus = '/app/appCourese/editRackingStatus',
+}
+export const list = (params) => defHttp.get({ url: Api.list, params });
+
+/**
+ * 删除单个
+ */
+export const deleteOne = (params, handleSuccess) => {
+  return defHttp.delete({ url: Api.deleteOne, 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 });
+};
+
+export const getDetaile = (params) => {
+  return defHttp.get({ url: Api.detaile, params });
+};
+
+export const getAddress = (params) => {
+  return defHttp.get({ url: Api.address, params });
+};
+/**
+ * 获取教练列表
+ * @param params
+ * @returns
+ */
+export const getCoachList = (params) => {
+  return defHttp.get({ url: Api.Coach, params });
+};
+
+/**课程价格规则表-通过课程id查询
+ *
+ * @param params
+ * @returns
+ */
+export const queryCourseList = (params) => {
+  return defHttp.get({ url: Api.queryCourseList, params });
+};
+/**
+ * 课程价格规则表-补课列表编辑
+ * @param params
+ * @returns
+ */
+export const editPriceRules = (params) => {
+  return defHttp.post({ url: Api.editPriceRules, params });
+};
+
+export const updateStatus = (params) => {
+  return defHttp.put({ url: `${Api.updateStatus}?appCourseId=${params.id}&rackingStatus=${params.rackingStatus}` });
+};

+ 57 - 0
src/views/Finance/balance/balance.data.ts

@@ -0,0 +1,57 @@
+import { BasicColumn } from '/@/components/Table';
+import { FormSchema } from '/@/components/Table';
+import { useUserStore } from '/@/store/modules/user';
+// import { Business, getProject } from '../gymnasiumBag/gymnasiumBag.api';
+import { storeToRefs } from 'pinia';
+const { userInfo } = storeToRefs(useUserStore());
+//列表数据
+export const columns: BasicColumn[] = [
+  {
+    title: '序号',
+    dataIndex: 'index',
+    width: 50,
+    customRender: ({ index }) => index + 1, // 渲染为从1开始的索引
+  },
+  {
+    title: '店铺名称',
+    align: 'center',
+    dataIndex: 'name',
+  },
+  {
+    title: '图片',
+    align: 'center',
+    dataIndex: 'cover',
+    slots: {
+      customRender: 'img',
+    },
+  },
+  {
+    title: '待结算(元)',
+    align: 'center',
+    dataIndex: 'to_be_settled',
+  },
+  {
+    title: '可用余额(元)',
+    align: 'center',
+    dataIndex: 'to_be_settled',
+  },
+  {
+    title: '已到账(元)',
+    align: 'center',
+    dataIndex: 'received',
+  },
+  {
+    title: '更新时间',
+    align: 'center',
+    dataIndex: 'updateTime',
+  },
+];
+//查询数据
+export const searchFormSchema: FormSchema[] = [
+  {
+    field: 'name',
+    label: '店铺名称',
+    component: 'Input',
+    colProps: { span: 6 },
+  },
+];

+ 164 - 0
src/views/Finance/balance/index.vue

@@ -0,0 +1,164 @@
+<template>
+  <div>
+    <!--引用表格-->
+    <BasicTable @register="registerTable">
+      <!--插槽:table标题-->
+      <template #tableTitle>
+        <a-button
+          type="primary"
+          v-auth="'app:appCourese:add'"
+          @click="router.push({ name: 'businessManagement-publishcourses', query: { type: 0 } })"
+          preIcon="ant-design:plus-outlined"
+        >
+          新增</a-button
+        >
+      </template>
+      <!--操作栏-->
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
+      </template>
+      <!--字段回显插槽-->
+      <template v-slot:bodyCell="{ column, record, index, text }"> </template>
+      <template #price="{ record }"> {{ record.sellingPrice }}/{{ record.originalPrice }} </template>
+      <template #priceType="{ record }">
+        <Switch v-model:checked="record.rackingStatus" :checked-value="0" :un-checked-value="1" @change="handleSwich(record)"></Switch>
+      </template>
+      <template #totalNum="{ record }">
+        <div>{{ record.totalNum }}课时</div>
+        {{ record.startTime }}-{{ record.endTime }}
+      </template>
+      <template #img="{ text }">
+        <TableImg :img-list="[text]" :size="60" simpleShow></TableImg>
+      </template>
+    </BasicTable>
+    <!-- 表单区域 -->
+  </div>
+</template>
+
+<script lang="ts" name="courses" setup>
+  import { Switch } from 'ant-design-vue';
+  import { router } from '/@/router';
+  import { ref, reactive, computed, unref } from 'vue';
+  import { BasicTable, TableImg, TableAction } from '/@/components/Table';
+  import { useModal } from '/@/components/Modal';
+  import { useListPage } from '/@/hooks/system/useListPage';
+  import { columns, searchFormSchema } from './balance.data';
+  import { list, deleteOne, updateStatus, queryCourseList } from './balance.api';
+  import { useUserStore } from '/@/store/modules/user';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { useRouteTabText } from '/@/hooks/web/useRouteTab';
+  const queryParam = reactive<any>({});
+  const userStore = useUserStore();
+  const { createMessage } = useMessage();
+
+  //注册model
+  const [registerModal, { openModal }] = useModal();
+  //注册table数据
+  const { prefixCls, tableContext } = useListPage({
+    tableProps: {
+      title: 'courses',
+      api: list,
+      columns,
+      formConfig: {
+        //labelWidth: 120,
+        schemas: searchFormSchema,
+        autoSubmitOnEnter: true,
+        showAdvancedButton: false,
+        fieldMapToNumber: [],
+        fieldMapToTime: [],
+        autoAdvancedCol: 4,
+      },
+
+      actionColumn: {
+        width: 180,
+        fixed: 'right',
+        defaultHidden: true,
+      },
+      beforeFetch: (params) => {
+        return Object.assign(params, queryParam);
+      },
+    },
+  });
+
+  const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
+  /**
+   * 编辑事件
+   */
+  function handleView(record: Recordable) {
+    router.push({ name: 'businessManagement-publishcourses', query: { type: 2, id: record.id } });
+  }
+  function handleEdit(record: Recordable) {
+    router.push({ name: 'businessManagement-publishcourses', query: { type: 1, id: record.id } });
+  }
+  /**
+   * 删除事件
+   */
+  async function handleDelete(record) {
+    await deleteOne({ id: record.id }, handleSuccess);
+  }
+
+  /**
+   * 成功回调
+   */
+  function handleSuccess() {
+    (selectedRowKeys.value = []) && reload();
+  }
+  /**
+   * 操作栏
+   */
+  function getTableAction(record) {
+    return [
+      {
+        label: '查看',
+        onClick: handleView.bind(null, record),
+      },
+      {
+        label: '编辑',
+        onClick: handleEdit.bind(null, record),
+        auth: 'app:appCourese:edit',
+        disabled: record.ifThereIsAnOrder,
+        tooltip: record.ifThereIsAnOrder ? '已有订单产生,不能编辑' : false,
+      },
+    ];
+  }
+  /**
+   * 下拉操作栏
+   */
+  function getDropDownAction(record) {
+    return [
+      {
+        label: '删除',
+        popConfirm: {
+          title: '是否确认删除',
+          confirm: handleDelete.bind(null, record),
+          placement: 'topLeft',
+        },
+        auth: 'app:appCourese:delete',
+      },
+      {
+        label: '编辑补课课表',
+        onClick: handleEditCourses.bind(null, record),
+        auth: 'app:appCourese:edit',
+      },
+    ];
+  }
+  async function handleEditCourses(record) {
+    const res = await queryCourseList({ coursesType: 1, id: record.id });
+    openModal(true, {
+      record: res ? { dtoList: res, name: record.name, id: record.id } : record,
+      isUpdate: true,
+      showFooter: true,
+    });
+  }
+  useRouteTabText(['发布课程', '编辑课程', '查看课程']);
+  async function handleSwich(record) {
+    await updateStatus({ id: record.id, rackingStatus: record.rackingStatus });
+  }
+</script>
+
+<style lang="less" scoped>
+  :deep(.ant-picker),
+  :deep(.ant-input-number) {
+    width: 100%;
+  }
+</style>

+ 125 - 0
src/views/Finance/shopBalance/index.vue

@@ -0,0 +1,125 @@
+<template>
+  <div>
+    <a-card class="ma2">
+      <div class="flex justify-between space-x-4">
+        <div class="flex-1 text-center">
+          <a-tooltip>
+            <template #title>用户购买商品后,增加待结算,退款后,减少待结算</template>
+            <div
+              >待结算(元)
+              <Icon icon="ant-design:question-circle-outlined"></Icon>
+            </div>
+          </a-tooltip>
+          <CountTo :endVal="cardDataList[0].toBeSettled" decimals="2" :style="{ fontSize: '34px' }"></CountTo>
+        </div>
+        <div class="flex-1 text-center">
+          <a-tooltip>
+            <template #title>商品进行分账成功后,增加可用余额</template>
+            <div
+              >可用余额(元)
+              <Icon icon="ant-design:question-circle-outlined"></Icon>
+            </div>
+            <CountTo :endVal="cardDataList[0].available" decimals="2" :style="{ fontSize: '34px' }"></CountTo>
+          </a-tooltip>
+        </div>
+        <div class="flex-1 text-center">
+          <a-tooltip>
+            <template #title>分账成功后,T+1到账后,增加已到账</template>
+            <div
+              >已到账(元)
+              <Icon icon="ant-design:question-circle-outlined"></Icon>
+            </div>
+            <CountTo :endVal="cardDataList[0].received" decimals="2" :style="{ fontSize: '34px' }"></CountTo>
+          </a-tooltip>
+        </div>
+      </div>
+    </a-card>
+    <!--引用表格-->
+    <BasicTable @register="registerTable">
+      <!--插槽:table标题-->
+      <template #tableTitle></template>
+      <!--操作栏-->
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
+      </template>
+      <!--字段回显插槽-->
+      <template #amount_type="{ record }">
+        <a-tag color="cyan" v-if="record.amount_type == '待结算'">{{ record.amount_type }}</a-tag>
+        <a-tag color="orange" v-if="record.amount_type == '已结算'">{{ record.amount_type }}</a-tag>
+        <a-tag color="green" v-if="record.amount_type == '可用余额'">{{ record.amount_type }} </a-tag>
+      </template>
+    </BasicTable>
+    <!-- 表单区域 -->
+  </div>
+</template>
+
+<script lang="ts" name="courses" setup>
+  import { Switch } from 'ant-design-vue';
+  import { router } from '/@/router';
+  import { ref, reactive, computed, unref } from 'vue';
+  import { BasicTable, TableImg, TableAction } from '/@/components/Table';
+  import { useModal } from '/@/components/Modal';
+  import { useListPage } from '/@/hooks/system/useListPage';
+  import { columns, searchFormSchema } from './shopBalance.data';
+  import { list, cardData } from './shopBalance.api';
+  import { useUserStore } from '/@/store/modules/user';
+  import { useMessage } from '/@/hooks/web/useMessage';
+  import { useRouteTabText } from '/@/hooks/web/useRouteTab';
+  import CountTo from '@/components/CountTo/src/CountTo.vue';
+
+  const queryParam = reactive<any>({});
+  const userStore = useUserStore();
+  const { createMessage } = useMessage();
+
+  //注册model
+  const [registerModal, { openModal }] = useModal();
+  //注册table数据
+  const { prefixCls, tableContext } = useListPage({
+    tableProps: {
+      title: 'courses',
+      api: list,
+      columns,
+      formConfig: {
+        schemas: searchFormSchema,
+        autoSubmitOnEnter: true,
+        showAdvancedButton: true,
+        fieldMapToNumber: [],
+        fieldMapToTime: [],
+        autoAdvancedCol: 4,
+      },
+
+      actionColumn: {
+        width: 180,
+        fixed: 'right',
+        defaultHidden: true,
+      },
+      beforeFetch: (params) => {
+        return Object.assign(params, queryParam);
+        // console.log('params', params);
+      },
+    },
+  });
+
+  const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
+
+  const cardDataList = ref([{}]);
+
+  async function getCardData() {
+    const res = await cardData({});
+    if (res.length > 0) {
+      cardDataList.value = res;
+    } else {
+      cardDataList.value = [{ toBeSettled: 0, available: 0, received: 0 }];
+    }
+    console.log('cardData', res);
+  }
+
+  getCardData();
+</script>
+
+<style lang="less" scoped>
+  :deep(.ant-picker),
+  :deep(.ant-input-number) {
+    width: 100%;
+  }
+</style>

+ 12 - 0
src/views/Finance/shopBalance/shopBalance.api.ts

@@ -0,0 +1,12 @@
+import { defHttp } from '/@/utils/http/axios';
+import { useMessage } from '/@/hooks/web/useMessage';
+
+const { createConfirm } = useMessage();
+
+enum Api {
+  list = '/statisticsInfo/selectFundChanges',
+  cardData = '/statisticsInfo/findShopAccountOverviewDept',
+}
+export const list = (params) => defHttp.get({ url: Api.list, params });
+
+export const cardData = (params) => defHttp.get({ url: Api.cardData, params });

+ 97 - 0
src/views/Finance/shopBalance/shopBalance.data.ts

@@ -0,0 +1,97 @@
+import { BasicColumn } from '/@/components/Table';
+import { FormSchema } from '/@/components/Table';
+import { useUserStore } from '/@/store/modules/user';
+// import { Business, getProject } from '../gymnasiumBag/gymnasiumBag.api';
+import { storeToRefs } from 'pinia';
+
+const { userInfo } = storeToRefs(useUserStore());
+//列表数据
+export const columns: BasicColumn[] = [
+  {
+    title: '序号',
+    dataIndex: 'index',
+    width: 50,
+    customRender: ({ index }) => index + 1, // 渲染为从1开始的索引
+  },
+  {
+    title: '收支类型',
+    align: 'center',
+    dataIndex: 'income_expense_type',
+  },
+  {
+    title: '金额类型',
+    align: 'center',
+    dataIndex: 'amount_type',
+    slots: { customRender: 'amount_type' },
+  },
+  {
+    title: '改变前金额(元)',
+    align: 'center',
+    dataIndex: 'amount_before',
+  },
+  {
+    title: '改变后金额(元)',
+    align: 'center',
+    dataIndex: 'amount_after',
+  },
+  {
+    title: '改变金额(元)',
+    align: 'center',
+    dataIndex: 'change_amount',
+  },
+  {
+    title: '资金变化原因',
+    align: 'center',
+    dataIndex: 'change_reason',
+  },
+  {
+    title: '创建时间',
+    align: 'center',
+    dataIndex: 'create_time',
+  },
+];
+//查询数据
+export const searchFormSchema: FormSchema[] = [
+  {
+    field: 'incomeExpenseType',
+    label: '收支类型',
+    component: 'Select',
+    componentProps: {
+      options: [
+        { label: '全部', value: '全部' },
+        { label: '收入', value: '收入' },
+        { label: '支出', value: '支出' },
+      ],
+    },
+    colProps: { span: 4 },
+  },
+  {
+    field: 'amountType',
+    label: '金额类型',
+    component: 'Select',
+    componentProps: {
+      options: [
+        { label: '全部', value: '全部' },
+        { label: '可用余额', value: '可用余额' },
+        { label: '待结算', value: '待结算' },
+        { label: '已结算', value: '已结算' },
+      ],
+    },
+    colProps: { span: 4 },
+  },
+  {
+    field: 'changeReason',
+    label: '资金变化原因',
+    componentProps: {
+      options: [
+        { label: '全部', value: '全部' },
+        { label: '用户支付', value: '用户支付' },
+        { label: '用户退款', value: '用户退款' },
+        { label: '分账', value: '分账' },
+        { label: '银行卡到账', value: '银行卡到账' },
+      ],
+    },
+    component: 'Select',
+    colProps: { span: 6 },
+  },
+];

+ 5 - 4
src/views/dashboard/Analysis/api.ts

@@ -3,9 +3,10 @@ import { defHttp } from '/@/utils/http/axios';
 enum Api {
   loginfo = '/sys/loginfo',
   visitInfo = '/sys/visitInfo',
-  indexData = '/statisticsInfo/findByStatistics',
-  storeData = '/statisticsInfo/findByShopMoneyList',
-  goodsData = '/statisticsInfo/findByShopSumList',
+  indexData = '/statisticsInfo/findIndexStatistics',
+  chartData='/statisticsInfo/findMonthSaleTrend',
+  storeData = '/statisticsInfo/findByDeptSum',
+  goodsData = '/statisticsInfo/findByShopSum',
 }
 /**
  * 日志统计信息
@@ -19,6 +20,6 @@ export const getLoginfo = (params) => defHttp.get({ url: Api.loginfo, params },
 export const getVisitInfo = (params) => defHttp.get({ url: Api.visitInfo, params }, { isTransformResponse: false });
 
 export const getIndexData = () => defHttp.get({ url: Api.indexData });
-
+export const getChartData = () => defHttp.get({ url: Api.chartData });
 export const getStoreData = (params) => defHttp.get({ url: Api.storeData, params });
 export const getGoodsData = (params) => defHttp.get({ url: Api.goodsData, params });

+ 9 - 10
src/views/dashboard/Analysis/components/Line.vue

@@ -6,22 +6,21 @@
   import { useECharts } from '/@/hooks/web/useECharts';
   import dayjs from 'dayjs';
   function generateCurrentMonthDays(chartData: any[] = []) {
-    const days: any = [];
-    const values: any[] = [];
+    const days: string[] = [];
+    const values: number[] = [];
     const daysInMonth = dayjs().daysInMonth();
-
-    // 创建一个映射,将dateDailyDate作为键,对应的数值作为值
+    // 创建一个映射,将 date 作为键,dailySalesAmount 作为值
     const dataMap: Record<string, number> = {};
     chartData.forEach((item) => {
-      if (item.dateDailyDate) {
-        dataMap[item.dateDailyDate] = item.expectIncomeMoney || 0;
+      if (item.date) {
+        const dateKey = dayjs(item.date).format('M/D');
+        dataMap[dateKey] = item.dailySalesAmount || 0;
       }
     });
     for (let i = 1; i <= daysInMonth; i++) {
-      const dayStr = `${String(dayjs().month() + 1).padStart(2, '0')}/${String(i).padStart(2, '0')}`;
-      const formattedDayStr = `${dayjs().month() + 1}/${i}`;
-      days.push(formattedDayStr);
-      values.push(dataMap[dayStr] || null);
+      const dayStr = `${dayjs().month() + 1}/${i}`;
+      days.push(dayStr);
+      values.push(dataMap[dayStr] || 0);
     }
     return { days, values };
   }

+ 62 - 36
src/views/dashboard/Analysis/index.vue

@@ -11,15 +11,15 @@
           <GradientBg :gradient-color="getGradientColor(item.color)" class="flex-1">
             <h3 class="text-16px">{{ item.title }}</h3>
             <div class="flex">
-              <CountTo :endVal="item.value" :style="{ fontSize: '34px' }"> </CountTo>
-              <div class="ml12px mt25px"> {{ item.unit }} </div>
+              <CountTo :endVal="item.value" decimals="2" :style="{ fontSize: '34px' }"></CountTo>
+              <div class="ml12px mt25px"> {{ item.unit }}</div>
             </div>
             <div class="flex justify-between pt-12px">
-              <Icon :icon="item.icon" :size="28"> </Icon>
+              <Icon :icon="item.icon" :size="28"></Icon>
               <div class="text-18px" v-if="item.Proportion != null">
                 环比:<span> {{ item.Proportion > 0 ? '+' : '' }} {{ item.Proportion }} %</span>
               </div>
-              <div v-else> 无环比数据 </div>
+              <div v-else> 无环比数据</div>
             </div>
           </GradientBg>
         </div>
@@ -32,7 +32,7 @@
     </div>
 
     <div class="mt24px grid gap-3" :class="[!getIsMerchant ? 'lg:grid-cols-2 sm:grid-cols-1' : '']">
-      <a-card :bordered="false" title="门店销售额排行" v-if="!getIsMerchant">
+      <a-card :bordered="false" title="门店销售额排行" v-if="!getIsMerchant" >
         <template #extra>
           <a-radio-group v-model:value="storeBtn" button-style="solid">
             <a-radio-button :value="1">今日</a-radio-button>
@@ -40,22 +40,24 @@
             <a-radio-button :value="3">本月</a-radio-button>
           </a-radio-group>
         </template>
-        <a-list item-layout="horizontal" :data-source="storeDataList">
-          <template #renderItem="{ item, index }">
-            <a-badge-ribbon placement="start" :text="index + 1" :color="index == 0 ? 'red' : index == 1 ? 'green' : index == 2 ? 'volcano' : ''">
-              <a-list-item>
-                <template #actions>
-                  <span> {{ item.saleMoney }} </span>
-                </template>
-                <a-list-item-meta>
-                  <template #title>
-                    <span class="ml40px">{{ item.deptName }} </span>
+<!--        <div class="overflow-y-scroll pl-20px">-->
+          <a-list item-layout="horizontal" :data-source="storeDataList">
+            <template #renderItem="{ item, index }">
+              <a-badge-ribbon placement="start" :text="index + 1" :color="index == 0 ? 'red' : index == 1 ? 'green' : index == 2 ? 'volcano' : ''">
+                <a-list-item>
+                  <template #actions>
+                    <span> {{ item.total_price }} </span>
                   </template>
-                </a-list-item-meta>
-              </a-list-item>
-            </a-badge-ribbon>
-          </template>
-        </a-list>
+                  <a-list-item-meta>
+                    <template #title>
+                      <span class="ml40px">{{ item.name }} </span>
+                    </template>
+                  </a-list-item-meta>
+                </a-list-item>
+              </a-badge-ribbon>
+            </template>
+          </a-list>
+<!--        </div>-->
       </a-card>
       <a-card :bordered="false" title="商品销量排行">
         <template #extra>
@@ -65,19 +67,25 @@
             <a-radio-button :value="3">本月</a-radio-button>
           </a-radio-group>
         </template>
+        <div class="grid grid-cols-4 text-center font-bold mb12px">
+          <div class="text-left">排名</div>
+          <div class="text-left">商品名称</div>
+          <div>销量</div>
+          <div>销售额(元)</div>
+        </div>
         <a-list item-layout="horizontal" :data-source="goodsDataList">
           <template #renderItem="{ item, index }">
             <a-badge-ribbon placement="start" :text="index + 1" :color="index == 0 ? 'red' : index == 1 ? 'green' : index == 2 ? 'volcano' : ''">
               <a-list-item>
                 <template #actions>
-                  <span> {{ item.totalPrice }} </span>
+                  <span class="w-56 block"> {{ item.total_price }} </span>
                 </template>
                 <a-list-item-meta>
                   <template #title>
-                    <span class="ml40px">{{ item.shopName }} </span>
+                    <span class="ml180px">{{ item.product_name }} </span>
                   </template>
                 </a-list-item-meta>
-                <div> {{ item.productCount }}</div>
+                <div> {{ item.total_quantity }}</div>
               </a-list-item>
             </a-badge-ribbon>
           </template>
@@ -92,17 +100,21 @@
   import CountTo from '/@/components/CountTo/src/CountTo.vue';
   import { createReusableTemplate } from '@vueuse/core';
   import { ref, unref, watch } from 'vue';
+
   const { getIsMerchant } = storeToRefs(useUserStore());
-  import { getGoodsData, getIndexData, getStoreData } from './api';
+  import { getGoodsData, getIndexData, getStoreData, getChartData } from './api';
   import { storeToRefs } from 'pinia';
   import { useUserStore } from '/@/store/modules/user';
+
   const storeBtn = ref(1);
   const goodsBtn = ref(1);
   const storeDataList = ref([]);
   const goodsDataList = ref([]);
+
   interface GradientBgProps {
     gradientColor: string;
   }
+
   interface CardData {
     key: string;
     title: string;
@@ -115,6 +127,7 @@
     icon: string;
     Proportion: number;
   }
+
   const [DefineGradientBg, GradientBg] = createReusableTemplate<GradientBgProps>();
   const cardData = ref<CardData[]>([
     {
@@ -190,36 +203,49 @@
       }
     }
   );
+
   function getGradientColor(color: CardData['color']) {
     return `linear-gradient(to bottom right, ${color.start}, ${color.end})`;
   }
+
   async function getDataIndex() {
     const res = await getIndexData();
-    unref(cardData)[0].value = res.saleMoney;
-    unref(cardData)[0].Proportion = res.saleMoneyChain;
-    unref(cardData)[1].value = res.effectiveOrderNum;
-    unref(cardData)[1].Proportion = res.effectiveOrderNumChain;
-    unref(cardData)[2].value = res.expectIncomeMoney;
-    unref(cardData)[2].Proportion = res.expectIncomeMoneyChain;
-    unref(cardData)[3].value = res.consumeNumber;
-    unref(cardData)[3].Proportion = res.consumeNumberChain;
-    unref(cardData)[4].value = res.addNumber;
-    unref(cardData)[4].Proportion = res.addNumberChain;
-    chartData.value = res.findByStatisticsChartVOList;
+    unref(cardData)[0].value = res.salesAmount;
+    unref(cardData)[0].Proportion = res.salesGrowthRate;
+    unref(cardData)[1].value = res.validOrderCount;
+    unref(cardData)[1].Proportion = res.validOrderGrowthRate;
+    unref(cardData)[2].value = res.expectedIncome;
+    unref(cardData)[2].Proportion = res.expectedIncomeGrowthRate;
+    unref(cardData)[3].value = res.platformConsumptionUsers;
+    unref(cardData)[3].Proportion = res.platformConsumptionGrowthRate;
+    unref(cardData)[4].value = res.newUsersCount;
+    unref(cardData)[4].Proportion = res.newUsersGrowthRate;
+    // chartData.value = res.findByStatisticsChartVOList;
   }
+
   async function getStoreDataList() {
     const res = await getStoreData({ type: storeBtn.value });
     console.log(res, 'getStoreDataList');
     storeDataList.value = res;
   }
-  getStoreDataList();
 
+  // 图表
+  async function getChartDataList() {
+    const res = await getChartData();
+    console.log(res, '--图表数据');
+    chartData.value = res;
+  }
+
+  getStoreDataList();
   getDataIndex();
+  getChartDataList();
+
   async function getGoodsList() {
     const res = await getGoodsData({ type: goodsBtn.value });
     console.log(res, 'getGoodsList');
     goodsDataList.value = res;
   }
+
   getGoodsList();
 </script>
 

+ 15 - 3
src/views/orderManagement/order/index.vue

@@ -84,7 +84,7 @@
   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 } from './order.api';
+  import { list, exportData, queryEvents, queryProject, putProfitSharing, putQueryProfitSharing } from './order.api';
   import { useUserStore } from '/@/store/modules/user';
   import { useMessage } from '/@/hooks/web/useMessage';
 
@@ -107,7 +107,7 @@
       },
       inset: true,
       actionColumn: {
-        width: 120,
+        width: 200,
         fixed: 'right',
       },
       beforeFetch: (params) => {
@@ -212,10 +212,17 @@
     });
   }
 
+  async function querySharingInfo(record) {
+    reload();
+    await putQueryProfitSharing({ orderCode: record.orderCode });
+  }
+
   /**
    * 操作栏
    */
   function getTableAction(record) {
+    console.log('表格数据', record);
+    console.log('分账:', record.orProfitSharing == 1 && record.profitSharingStatus == 0);
     return [
       {
         label: '查看',
@@ -225,7 +232,12 @@
       {
         label: '分账',
         onClick: handleConfirm.bind(null, record),
-        isShow: record.orProfitSharing == 1,
+        ifShow:record.orProfitSharing == 1 && record.profitSharingStatus == 0, //record.orProfitSharing:0:不支持分账 1:支持分账
+      },
+      {
+        label: '查询分账',
+        onClick: querySharingInfo.bind(null, record),
+        ifShow: record.orProfitSharing == 1 && record.profitSharingStatus != 0,
       },
     ];
   }

+ 6 - 0
src/views/orderManagement/order/order.api.ts

@@ -7,6 +7,8 @@ enum Api {
   queryProject = '/app/appOrder/exportConditionByProjectName',
   exportData = '/app/appOrder/exportCondition',
   profitSharing = '/app/appOrder/profitSharing',
+  queryProfitSharing = '/app/appOrder/profitSharingReflush',
+
 }
 
 /**
@@ -22,6 +24,10 @@ export const putProfitSharing = (params) => {
   const queryString = new URLSearchParams(params).toString();
   return defHttp.put({ url: `${Api.profitSharing}?${queryString}` });
 };
+export const putQueryProfitSharing = (params) => {
+  const queryString = new URLSearchParams(params).toString();
+  return defHttp.put({ url: `${Api.queryProfitSharing}?${queryString}` });
+};
 export const exportData = (params) =>
   defHttp.post(
     {

+ 214 - 0
src/views/orderManagement/refundOrder/components/orderModelView.vue

@@ -0,0 +1,214 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" title="查看" width="1000px" destroyOnClose>
+    <div class="px3 max-h-900px overflow-y-scroll" v-if="orderInfo">
+      <div class="flex items-center font-semibold">
+        <div>订单编号:{{ orderInfo.orderCode }}</div>
+        <div class="ml-3">下单时间:{{ orderInfo.createTime }} </div>
+      </div>
+      <div class="mt3">
+        <div v-if="orderInfo.orderType != 1 && orderInfo.orderType != 2"
+          >共{{ count }}人 <span class="text-gray">{{ orderStatus[orderInfo.orderStatus] }}</span>
+        </div>
+        <div v-else> 共 {{ count }} 场 </div>
+        <div class="flex items-center mt3" v-if="orderInfo.orderStatus == 1 || orderInfo.orderStatus == 2">
+          <div class="flex items-center mr2" v-for="item in orderInfo.proInfoList" :key="item.id">
+            <!-- //6为保险不展示 -->
+            <template v-if="item.type != 6">
+              <div class="mr3 text-gray" v-if="orderInfo.orderType != 1 && orderInfo.orderType != 2">{{ item.userName }} </div>
+              <div class="mr3 text-gray" :class="[item.orderStatus == 2 ? 'line-through' : '']" v-else> {{ item.ticketNo }} </div>
+              <div class="text-gray">{{ orderStatus[item.orderStatus] }} </div>
+            </template>
+          </div>
+        </div>
+        <div v-if="orderInfo.orderStatus == 0">
+          <div>商品已拍下,等待买家付款</div>
+          <div class="text-gray flex items-center">
+            如买家未在
+            <StatisticCountdown
+              @finish="finish"
+              :value="dayjs(orderInfo.createTime).add(15, 'minute').valueOf()"
+              :valueStyle="{ fontSize: '18px' }"
+              class="mx2"
+            />
+            内付款,订单将自动关闭
+          </div>
+        </div>
+      </div>
+      <Divider></Divider>
+      <div class="grid lg:grid-cols-3 gap-2 sm:grid-cols-1">
+        <div>
+          <div>使用地信息 </div>
+          <div class="text-gray">地点:{{ orderInfo.siteName }}</div>
+          <div class="text-gray">地址:{{ orderInfo.address }} </div>
+        </div>
+        <div v-if="!getGameCertification">
+          <div>付款信息 </div>
+          <div class="text-gray">实付金额:{{ orderInfo.price || 0 }}元</div>
+          <div class="text-gray">付款时间:{{ orderInfo.payTime || '--' }}</div>
+        </div>
+        <div>
+          <div>买家信息 </div>
+          <div class="text-gray">买家昵称:{{ orderInfo.nikeName }}</div>
+          <div class="text-gray">买家电话:{{ orderInfo.phoneNumber }}</div>
+        </div>
+        <div v-if="getGameCertification">
+          <div>团队信息 </div>
+          <div class="text-gray">队名:{{ getGameCertification.teamName }}</div>
+          <div class="text-gray flex items-center" v-if="getImageList.length"
+            >队徽:
+            <div class="overflow-x-scroll w220px flex items-center">
+              <div v-for="item in getImageList" :key="item" class="flex items-center">
+                <div class="mr2">
+                  <Image :width="40" :height="40" class="rounded-16px mr2" :src="item" />
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+      <Divider></Divider>
+      <TypographyTitle :level="5">订单信息</TypographyTitle>
+      <div class="w-full">
+        <Table :columns="orderCloumsData" :dataSource="orderInfo.proInfoList" bordered :pagination="{ hideOnSinglePage: true }"></Table>
+      </div>
+      <div class="mt3">
+        <Descriptions title="费用信息" bordered layout="vertical">
+          <DescriptionsItem>
+            <template #label>
+              <div class="flex items-center justify-between">
+                <div>费用信息</div>
+                <div>金额/元</div>
+              </div>
+            </template>
+            <div>
+              <div class="flex items-center justify-between">
+                <div>商品总额</div>
+                <div>{{ orderInfo.totalPrice || 0 }}</div>
+              </div>
+              <Divider></Divider>
+            </div>
+            <div v-if="orderInfo.tdiscounts">
+              <div class="flex items-center justify-between">
+                <div>团购优惠</div>
+                <div>- {{ orderInfo.tdiscounts || 0 }}</div>
+              </div>
+              <Divider></Divider>
+            </div>
+            <div v-if="orderInfo.price">
+              <div class="flex items-center justify-between">
+                <div>实际付款</div>
+                <div>{{ orderInfo.price || 0 }}</div>
+              </div>
+              <Divider></Divider>
+            </div>
+            <div v-if="orderInfo.sdiscounts">
+              <div class="flex items-center justify-between">
+                <div>试听优惠</div>
+                <div>{{ orderInfo.sdiscounts || 0 }}</div>
+              </div>
+              <Divider></Divider>
+            </div>
+            <div v-if="orderInfo.price">
+              <div class="flex items-center justify-between">
+                <div>应付款</div>
+                <div>{{ orderInfo.price || 0 }}</div>
+              </div>
+              <Divider></Divider>
+            </div>
+          </DescriptionsItem>
+        </Descriptions>
+      </div>
+      <div class="mt3">
+        <TypographyTitle :level="5">使用记录</TypographyTitle>
+        <Table :columns="getColumText(orderInfo.orderType)" :dataSource="orderInfo.isinList" :pagination="{ hideOnSinglePage: true }"></Table>
+      </div>
+      <div class="mt3" v-if="normalClass?.length">
+        <TypographyTitle :level="5">(正常课)核销记录</TypographyTitle>
+        <Table :columns="verificationRecordColumns" :dataSource="normalClass" :pagination="{ hideOnSinglePage: true }"></Table>
+      </div>
+      <div class="mt3" v-if="supplementClass?.length">
+        <TypographyTitle :level="5">(补课)核销记录</TypographyTitle>
+        <Table :columns="verificationRecordColumns" :dataSource="supplementClass" :pagination="{ hideOnSinglePage: true }"></Table>
+      </div>
+      <div class="mt3" v-if="orderInfo?.gameScheduleVOList?.length">
+        <TypographyTitle :level="5">赛程安排</TypographyTitle>
+        <Table :columns="gameScheduleVOListColumns" :dataSource="orderInfo?.gameScheduleVOList" :pagination="{ hideOnSinglePage: true }"></Table>
+      </div>
+    </div>
+  </BasicModal>
+</template>
+<script lang="ts" setup>
+  import { Image } from 'ant-design-vue';
+  import { TypographyTitle, Divider, Table, Descriptions, DescriptionsItem, StatisticCountdown } from 'ant-design-vue';
+  import { computed, ref } from 'vue';
+  import { BasicModal, useModalInner } from '/@/components/Modal';
+  import { queryByid, AppOrderInfoVO } from '../order.api';
+  import { orderStatus, orderColum, getColumText, verificationRecordColumns, gameScheduleVOListColumns } from '../order.data';
+  import dayjs from 'dayjs';
+  const orderId = ref();
+  const orderInfo = ref<AppOrderInfoVO>();
+  const [registerModal, { setModalProps }] = useModalInner(async (data) => {
+    setModalProps({ loading: true, showCancelBtn: false, showOkBtn: false });
+    orderInfo.value = undefined;
+    orderId.value = data.record.id;
+    const res = await queryByid(data.record.id);
+    orderInfo.value = res;
+    setModalProps({ loading: false });
+  });
+  const count = computed(() => {
+    return orderInfo.value?.proInfoList?.filter((it) => it.type != 6).length;
+  });
+  async function finish() {
+    const res = await queryByid(orderId.value);
+    orderInfo.value = res;
+  }
+  const normalClass = computed(() => {
+    const newList = orderInfo.value?.verificationRecordDTOList?.filter((it) => it.coursesType == 0);
+    return newList?.length ? newList[0].verificationRecordList : [];
+  });
+  const supplementClass = computed(() => {
+    const newList = orderInfo.value?.verificationRecordDTOList?.filter((it) => it.coursesType == 1);
+    return newList?.length ? newList[0].verificationRecordList : [];
+  });
+  const getGameCertification = computed(() => {
+    if (orderInfo.value?.gameCertification) {
+      return JSON.parse(orderInfo.value?.gameCertification);
+    }
+    return '';
+  });
+  const getImageList = computed(() => {
+    if (getGameCertification.value && getGameCertification.value.teamEmblemImg) {
+      console.log(getGameCertification.value.teamEmblemImg.split(','), 'getGameCertification.value.teamEmblemImg');
+      return getGameCertification.value.teamEmblemImg.split(',');
+    }
+    return [];
+  });
+  const orderCloumsData = computed(() => {
+    if (orderInfo.value?.orderType == 0) {
+      const newColum = [...orderColum];
+
+      newColum.splice(1, 1, {
+        title: '使用日期-时段',
+        dataIndex: 'useTime',
+        width: 380,
+        align: 'center',
+        customRender: ({ record }) => {
+          return record.type != 6 ? record.useDateStr + '-' + record.frameTimeStr : '无';
+        },
+      });
+      newColum.splice(2, 1, {
+        title: '使用人/联系电话',
+        dataIndex: 'useTime',
+        width: 380,
+        align: 'center',
+        customRender: ({ record }) => {
+          return record.type != 6 ? record.userName + '-' + record.userPhone : '无';
+        },
+      });
+      console.log(newColum, 'newColum');
+
+      return newColum;
+    }
+    return orderColum;
+  });
+</script>

+ 273 - 0
src/views/orderManagement/refundOrder/index.vue

@@ -0,0 +1,273 @@
+<template>
+  <BasicTable @register="registerTable">
+    <!--操作栏-->
+    <template #action="{ record }">
+      <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
+    </template>
+    <template #goods="{ record }">
+      <div class="flex items-center h-20px text-16px">
+        <div class="font-semibold">订单编号:{{ record.orderCode }}</div>
+        <div class="ml3">下单时间:{{ record.createTime }}</div>
+        <div class="ml3 truncate w300px"
+          >店铺名称:
+
+          <a-tooltip>
+            <template #title>{{ record.orderType == 3 || record.orderType == 4 ? record.departName : record.siteName }} </template>
+            {{ record.orderType == 3 || record.orderType == 4 ? record.departName : record.siteName }}
+          </a-tooltip>
+        </div>
+      </div>
+      <div class="mt3 flex items-center border-b border-solid pb-3 h-90px" v-for="item in record.orderProInfoList" :key="item.id">
+        <Image :width="80" :height="80" class="rounded-16px" :src="item.productImage.split(',')[0]" v-if="item.productImage" />
+        <div class="ml3">{{ item.productName }}</div>
+      </div>
+    </template>
+    <template #price="{ record }">
+      <div class="h-20px"></div>
+      <div class="mt3 h-90px flex flex-col justify-center border-b border-solid" v-for="item in record.orderProInfoList" :key="item.id">
+        <div class="flex items-center" v-if="item.price > 0">
+          <div>¥{{ item.price || 0 }}</div>
+          <div class="line-through ml-3 text-gray">¥{{ item.originalPrice || 0 }}</div>
+        </div>
+        <div class="flex items-center" v-else>
+          <div>¥{{ item.originalPrice || 0 }}</div>
+          <!--          <div class="line-through ml-3 text-gray">¥{{ item.originalPrice || 0 }}</div>-->
+        </div>
+        <div class="text-gray">x{{ item.quantity }}</div>
+      </div>
+    </template>
+    <template #user="{ record }">
+      <div class="h-20px"></div>
+      <div class="mt3 h-90px flex flex-col justify-center border-b border-solid" v-for="item in record.orderProInfoList" :key="item.id">
+        <div>{{ item.userName || item.ticketNo || '无' }}</div>
+        <div class="text-gray">{{ item.userPhone }}</div>
+      </div>
+    </template>
+    <template #status="{ record }">
+      <div class="h-20px"></div>
+      <div class="mt3 h-90px flex flex-col justify-center border-b border-solid" v-for="item in record.orderProInfoList" :key="item.id">
+        <div v-if="item.type != 6">{{ orderStatus[item.orderStatus] }}</div>
+        <div v-else>无</div>
+      </div>
+    </template>
+    <template #After="{ record }">
+      <div class="h-20px"></div>
+      <div class="mt3 h-90px flex flex-col justify-center border-b border-solid" v-for="item in record.orderProInfoList" :key="item.id">
+        <div v-if="item.type != 6">{{ afterSaleStatus[item.afterSaleStatus] }}</div>
+        <div v-else>无</div>
+      </div>
+    </template>
+    <template #sharing="{ record }">
+      <a-tag color="pink" v-if="record.profitSharingStatus == 0">未分账</a-tag>
+      <a-tag color="cyan" v-if="record.profitSharingStatus == 1">分账中</a-tag>
+      <a-tag color="green" v-if="record.profitSharingStatus == 2">已分账</a-tag>
+    </template>
+  </BasicTable>
+  <orderModelView @register="registerModal"></orderModelView>
+  <a-modal v-model:open="openExportData" title="导出赛事名单" @ok="handleExportData" :confirmLoading="exportLoading">
+    <BasicForm :showActionButtonGroup="false" @register="registerForm" style="margin: 50px 50px 0 50px" />
+  </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 { 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 } from './order.api';
+  import { useUserStore } from '/@/store/modules/user';
+  import { useMessage } from '/@/hooks/web/useMessage';
+
+  const { createWarningModal } = useMessage();
+  const queryParam = reactive<any>({});
+  const userStore = useUserStore();
+  //注册model
+  const [registerModal, { openModal }] = useModal();
+  //注册table数据
+  const { prefixCls, tableContext } = useListPage({
+    tableProps: {
+      api: list,
+      columns,
+      formConfig: {
+        schemas: searchFormSchema,
+        autoSubmitOnEnter: true,
+        showAdvancedButton: true,
+        fieldMapToNumber: [],
+        fieldMapToTime: [['time', ['startTime', 'endTime'], 'YYYY-MM-DD HH:mm:ss']],
+      },
+      inset: true,
+      actionColumn: {
+        width: 120,
+        fixed: 'right',
+      },
+      beforeFetch: (params) => {
+        return Object.assign(params, { ...queryParam, orgCode: userStore.userInfo?.orgCode });
+      },
+    },
+  });
+
+  const [registerTable, { reload }, { selectedRowKeys }] = tableContext;
+  //自定义表单字段
+  const formSchemas: FormSchema[] = [
+    {
+      label: '赛事名称',
+      field: 'name',
+      component: 'ApiSelect',
+      required: true,
+      labelWidth: 100,
+      componentProps: {
+        api: queryEvents,
+        fieldNames: {
+          label: 'name',
+          value: 'id',
+        },
+        onChange: (value) => {
+          exportQueryParam.gameId = value;
+        },
+      },
+    },
+    {
+      label: '比赛项目',
+      field: 'project',
+      component: 'ApiSelect',
+      required: true,
+      labelWidth: 100,
+      componentProps: {
+        api: queryProject,
+        fieldNames: {
+          label: 'name',
+          value: 'id',
+        },
+        params: computed(() => {
+          return exportQueryParam.gameId ? { gameId: exportQueryParam.gameId } : {};
+        }),
+        onChange: (value) => {
+          exportQueryParam.projectId = value;
+        },
+      },
+    },
+    // {
+    //   label: '报名结束时间',
+    //   field: 'entryTime',
+    //   component: 'RangePicker',
+    //   labelWidth: 100,
+    //   required: true,
+    //   componentProps: {
+    //     onChange: (value) => {
+    //       exportQueryParam.startTime = value[0];
+    //       exportQueryParam.endTime = value[1];
+    //       console.log(value);
+    //     },
+    //   },
+    // },
+  ];
+
+  /**
+   * BasicForm绑定注册;
+   */
+  const [registerForm] = useForm({
+    //注册表单列
+    schemas: formSchemas,
+    showResetButton: false,
+    submitButtonOptions: { text: '提交', preIcon: '' },
+    actionColOptions: { span: 17 },
+  });
+
+  /**
+   * 编辑事件
+   */
+  function handleEdit(record: Recordable) {
+    openModal(true, {
+      record,
+    });
+  }
+
+  /**
+   * 确认分账
+   */
+  function handleConfirm(record) {
+    createWarningModal({
+      title: '提示',
+      content: '是否确认进行分账?',
+      okText: '确认',
+      cancelText: '取消',
+      okCancel: true,
+      onOk: async () => {
+        await putProfitSharing({ orderCode: record.orderCode });
+        await reload();
+      },
+      onCancel: () => {
+        reload();
+      },
+    });
+  }
+
+  /**
+   * 操作栏
+   */
+  function getTableAction(record) {
+    return [
+      {
+        label: '查看',
+        onClick: handleEdit.bind(null, record),
+        // auth: 'feedback:nm_feedback:edit',
+      },
+      {
+        label: '分账',
+        onClick: handleConfirm.bind(null, record),
+        isShow: record.orProfitSharing == 1,
+      },
+    ];
+  }
+
+  /**
+   * 下拉操作栏
+   */
+  function getDropDownAction(record) {
+    return [];
+  }
+
+  const openExportData = ref(false);
+
+  function handleExport() {
+    openExportData.value = true;
+    // message.error('记得提醒搞导出,现在暂时没有这个功能!');
+  }
+
+  // 提交导出
+  const exportQueryParam = reactive<any>({
+    gameId: null,
+    projectId: null,
+    startTime: null,
+    endTime: null,
+  });
+  const exportLoading = ref(false);
+  const handleExportData = async () => {
+    exportLoading.value = true;
+    try {
+      const response = await exportData(exportQueryParam);
+      const blob = new Blob([response], { type: 'application/vnd.ms-excel' });
+      const downloadUrl = window.URL.createObjectURL(blob);
+      const link = document.createElement('a');
+      link.href = downloadUrl;
+      link.download = '赛事名单.xlsx';
+      document.body.appendChild(link);
+      link.click();
+      document.body.removeChild(link);
+      window.URL.revokeObjectURL(downloadUrl);
+      message.success('导出成功!');
+    } catch (error) {
+      console.error('导出失败:', error);
+      message.error('导出失败,请稍后重试');
+    } finally {
+      exportLoading.value = false;
+      openExportData.value = false;
+    }
+  };
+</script>
+
+<style scoped></style>

+ 548 - 0
src/views/orderManagement/refundOrder/order.api.ts

@@ -0,0 +1,548 @@
+import { defHttp } from '/@/utils/http/axios';
+
+enum Api {
+  list = '/app/appOrder/queryPage',
+  queryByid = '/app/appOrder/queryInfoById',
+  queryEvents = '/app/appOrder/exportConditionByName',
+  queryProject = '/app/appOrder/exportConditionByProjectName',
+  exportData = '/app/appOrder/exportCondition',
+  profitSharing = '/app/appOrder/profitSharing',
+}
+
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) => defHttp.post({ url: Api.list, params });
+
+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 putProfitSharing = (params) => {
+  const queryString = new URLSearchParams(params).toString();
+  return defHttp.put({ url: `${Api.profitSharing}?${queryString}` });
+};
+export const exportData = (params) =>
+  defHttp.post(
+    {
+      url: Api.exportData,
+      params,
+      responseType: 'blob',
+    },
+    {
+      isTransformResponse: false, // 禁用默认的响应转换
+    }
+  );
+
+/**
+ * 返回数据对象 data
+ * 返回数据对象
+ *
+ * AppOrderInfoVO
+ */
+export interface AppOrderInfoVO {
+  /**
+   * 订单类型:0-学校 1-包场 2-无固定场 3-个人赛 4-团队赛 5-课程
+   */
+
+  orderType: number;
+
+  /**
+   * 地址
+   */
+  address?: string;
+  /**
+   * 下单时间
+   */
+  createTime?: string;
+  /**
+   * 赛程安排
+   */
+  gameScheduleVOList?: AppGameScheduleVO[];
+  /**
+   * ID
+   */
+  id?: string;
+  /**
+   * 使用记录
+   */
+  isinList?: AppIsinVO[];
+  /**
+   * 买家昵称
+   */
+  nikeName?: string;
+  /**
+   * 订单号
+   */
+  orderCode?: string;
+  /**
+   * 订单状态
+   */
+  orderStatus: number;
+  /**
+   * 付款时间
+   */
+  payTime?: string;
+  /**
+   * 买家电话
+   */
+  phoneNumber?: string;
+  /**
+   * 实际付款
+   */
+  price?: number;
+  /**
+   * 订单信息
+   */
+  proInfoList?: AppOrderProInfo[];
+  /**
+   * 试听优惠金额
+   */
+  sDiscounts?: number;
+  /**
+   * 地点
+   */
+  siteName?: string;
+  /**
+   * 团购优惠金额
+   */
+  tDiscounts?: number;
+  /**
+   * 商品总额
+   */
+  totalPrice?: number;
+  /**
+   * 核销记录
+   */
+  verificationRecordDTOList?: VerificationRecordDTO[];
+
+  [property: string]: any;
+}
+
+/**
+ * org.jeecg.modules.app.vo.AppGameScheduleVO
+ *
+ * AppGameScheduleVO
+ */
+export interface AppGameScheduleVO {
+  /**
+   * 安排
+   */
+  arrange?: string;
+  /**
+   * 结束时间
+   */
+  endTime?: string;
+  /**
+   * 赛事id
+   */
+  gameId?: string;
+  /**
+   * id
+   */
+  id?: string;
+  /**
+   * 比赛名称
+   */
+  name?: string;
+  /**
+   * 开始状态
+   */
+  startStatus?: string;
+  /**
+   * 开始时间
+   */
+  startTime?: string;
+
+  [property: string]: any;
+}
+
+/**
+ * org.jeecg.modules.system.app.vo.AppIsinVO
+ *
+ * AppIsinVO
+ */
+export interface AppIsinVO {
+  /**
+   * 用户ID(关联家庭用户表)
+   */
+  familyId?: string;
+  /**
+   * 用户名
+   */
+  familyUserName?: string;
+  /**
+   * 券码号
+   */
+  isinCode?: string;
+  /**
+   * 使用记录
+   */
+  isinList?: AppIsin[];
+  /**
+   * 手机号码
+   */
+  UserPhone?: string;
+
+  [property: string]: any;
+}
+
+/**
+ * AppIsin
+ */
+export interface AppIsin {
+  /**
+   * 创建人;创建人
+   */
+  createBy?: string;
+  /**
+   * 创建时间;创建时间
+   * 创建时间
+   */
+  createTime?: string;
+  /**
+   * 删除标志;删除状态(0-正常,1-已删除)
+   * 删除状态(0-正常,1-已删除)
+   */
+  delFlag?: number;
+  /**
+   * 到期时间
+   */
+  expireTime?: string;
+  /**
+   * 用户ID
+   * 用户ID(关联家庭用户表)
+   */
+  familyId?: string;
+  /**
+   * 用户名
+   */
+  familyUserName?: string;
+  /**
+   * 主键ID
+   */
+  id?: string;
+  /**
+   * 券状态  0-待使用 1-已使用 2-已失效
+   */
+  isinStatus?: number;
+  /**
+   * 订单编号
+   */
+  orderCode?: string;
+  /**
+   * 订单ID
+   */
+  orderId?: string;
+  /**
+   * 子订单商品ID
+   */
+  orderProInfoId?: string;
+  /**
+   * 部门编号
+   */
+  orgCode?: string;
+  /**
+   * 备注
+   */
+  remark?: string;
+  /**
+   * 系统状态;状态(0-正常,1-冻结)
+   * 系统状态(0-正常,1-冻结)
+   */
+  status?: number;
+  /**
+   * 券码号
+   */
+  ticketNo?: string;
+  /**
+   * 更新时间;更新时间
+   * 更新时间
+   */
+  updateTime?: string;
+  /**
+   * 使用地点
+   */
+  useAddress?: string;
+  /**
+   * 使用照片
+   */
+  useImage?: string;
+  /**
+   * 手机号码
+   */
+  UserPhone?: string;
+  /**
+   * 使用时间
+   */
+  useTime?: string;
+  /**
+   * 核验人ID
+   */
+  verifyUserId?: string;
+  /**
+   * 核验人
+   * 核验人名称
+   */
+  verifyUserName?: string;
+
+  [property: string]: any;
+}
+
+/**
+ * org.jeecg.modules.system.app.entity.AppOrderProInfo
+ *
+ * AppOrderProInfo
+ */
+export interface AppOrderProInfo {
+  /**
+   * 地点
+   */
+  address?: string;
+  /**
+   * 售后状态
+   */
+  afterSaleStatus?: number;
+  /**
+   * 创建人;创建人
+   */
+  createBy?: string;
+  /**
+   * 创建时间;创建时间
+   */
+  createTime?: string;
+  /**
+   * 删除标志;删除状态(0-正常,1-已删除)
+   */
+  delFlag?: number;
+  /**
+   * 过期时间
+   */
+  expireTime?: string;
+  /**
+   * 使用人ID
+   */
+  familyUserId?: string;
+  /**
+   * 时间段
+   */
+  frameTimeStr?: string;
+  /**
+   * 比赛日期
+   */
+  gameTimeStr?: string;
+  /**
+   * id
+   */
+  id?: string;
+  /**
+   * 订单id
+   * 订单编号
+   */
+  orderCode?: string;
+  /**
+   * 订单id
+   */
+  orderId?: string;
+  /**
+   * 订单状态
+   */
+  orderStatus: number;
+  /**
+   * 是否免费试听课(0-否 1-是)
+   */
+  orFreePro?: number;
+  /**
+   * 原价/元
+   */
+  originalPrice?: number;
+  /**
+   * 实际价格/元
+   */
+  price?: number;
+  /**
+   * 产品id;场地/赛事/课程
+   */
+  productId?: string;
+  /**
+   * 商品图片
+   */
+  productImage?: string;
+  /**
+   * 商品名称
+   */
+  productName?: string;
+  /**
+   * 数量
+   */
+  quantity?: number;
+  /**
+   * 系统状态;状态(0-正常,1-冻结)
+   */
+  status?: number;
+  /**
+   * 券号
+   */
+  ticketNo?: string;
+  /**
+   * 商品类型(0-学校 1-包场 2-无固定场 3-个人赛 4-团队赛 5-课程 6-保险)
+   */
+  type?: number;
+  /**
+   * 更新人;更新人
+   */
+  updateBy?: string;
+  /**
+   * 更新时间;更新时间
+   */
+  updateTime?: string;
+  /**
+   * 日期
+   */
+  useDateStr?: string;
+  /**
+   * 使用人
+   */
+  userName?: string;
+  /**
+   * 手机号
+   */
+  userPhone?: string;
+
+  [property: string]: any;
+}
+
+/**
+ * org.jeecg.modules.system.app.dto.VerificationRecordDTO
+ *
+ * VerificationRecordDTO
+ */
+export interface VerificationRecordDTO {
+  /**
+   * 课程类型(0-正常课 1-补课)
+   */
+  coursesType?: number;
+  /**
+   * 核销记录
+   */
+  verificationRecordList?: AppCoursesVerificationRecord[];
+
+  [property: string]: any;
+}
+
+/**
+ * AppCoursesVerificationRecord
+ */
+export interface AppCoursesVerificationRecord {
+  /**
+   * 上课时间
+   */
+  coursesEndTime?: string;
+  /**
+   * 课程ID
+   */
+  coursesId?: string;
+  /**
+   * 课时名称
+   */
+  coursesName?: string;
+  /**
+   * 课程小节ID
+   */
+  coursesPriceRuleId?: string;
+  /**
+   * 上课时间
+   */
+  coursesStartTime?: string;
+  /**
+   * 课程类型(0-正常课 1-补课)
+   */
+  coursesType?: number;
+  /**
+   * 创建人;创建人
+   */
+  createBy?: string;
+  /**
+   * 创建时间;创建时间
+   */
+  createTime?: string;
+  /**
+   * 删除标志;删除状态(0-正常,1-已删除)
+   */
+  delFlag?: number;
+  /**
+   * id
+   */
+  id?: string;
+  /**
+   * 订单编号
+   */
+  orderCode?: string;
+  /**
+   * 订单id
+   */
+  orderId?: string;
+  /**
+   * id
+   * 部门编号
+   */
+  orgCode?: string;
+  /**
+   * 是否延课(0-未延课 1-已延课)
+   */
+  orPostpone?: number;
+  /**
+   * 延课原因
+   */
+  postponeReason?: string;
+  /**
+   * 系统状态;状态(0-正常,1-冻结)
+   */
+  status?: number;
+  /**
+   * 更新人;更新人
+   */
+  updateBy?: string;
+  /**
+   * 更新时间;更新时间
+   */
+  updateTime?: string;
+  /**
+   * 使用人ID
+   */
+  useUserId?: string;
+  /**
+   * 使用人人脸照片
+   */
+  useUserImage?: string;
+  /**
+   * 使用人名称
+   */
+  useUserName?: string;
+  /**
+   * 使用人手机号
+   */
+  useUserPhone?: string;
+  /**
+   * 核验照片
+   */
+  verifyImage?: string;
+  /**
+   * 核销状态(0-未核销 1-已核销)
+   */
+  verifyStatus?: number;
+  /**
+   * 核验时间
+   */
+  verifyTime?: string;
+  /**
+   * 核验人ID
+   */
+  verifyUserId?: string;
+  /**
+   * 核验人名称
+   */
+  verifyUserName?: string;
+
+  [property: string]: any;
+}

+ 392 - 0
src/views/orderManagement/refundOrder/order.data.ts

@@ -0,0 +1,392 @@
+import { BasicColumn } from '/@/components/Table';
+import { FormSchema } from '/@/components/Table';
+import { h, VNode } from 'vue';
+import { TableColumnType, Image, Tag } from 'ant-design-vue';
+import dayjs from 'dayjs';
+//列表数据
+export const columns: BasicColumn[] = [
+  {
+    title: '商品',
+    align: 'left',
+    dataIndex: 'userName',
+    width: 820,
+    slots: { customRender: 'goods' },
+  },
+  {
+    title: '价格/数量',
+    align: 'left',
+    dataIndex: 'phone',
+    width: 120,
+    slots: { customRender: 'price' },
+  },
+  {
+    title: '使用人',
+    align: 'center',
+    dataIndex: 'feedbackType',
+    width: 120,
+    slots: { customRender: 'user' },
+  },
+  {
+    title: '订单状态',
+    align: 'center',
+    dataIndex: 'status',
+    width: 120,
+    slots: { customRender: 'status' },
+  },
+  {
+    title: '售后状态',
+    align: 'center',
+    dataIndex: 'feedbackImgList',
+    width: 120,
+    slots: { customRender: 'After' },
+  },
+  {
+    title: '分账状态',
+    align: 'center',
+    dataIndex: 'profitSharingStatus',
+    width: 120,
+    slots: { customRender: 'sharing' },
+  },
+  {
+    title: '实付金额',
+    align: 'center',
+    dataIndex: 'createTime',
+    width: 120,
+    customRender: ({ record }) => {
+      return h('div', {}, [h('div', {}, `¥${record.price || 0}`), h('div', { class: 'text-gray' }, `共${record.orderProInfoList.length}件`)]);
+    },
+  },
+];
+//查询数据
+export const searchFormSchema: FormSchema[] = [
+  {
+    label: '手机号码',
+    field: 'userPhone',
+    component: 'Input',
+  },
+  {
+    label: '退款编号',
+    field: 'orderCode',
+    component: 'Input',
+  },
+  {
+    label: '订单编号',
+    field: 'orderCode',
+    component: 'Input',
+  },
+  {
+    label: '下单时间',
+    field: 'time',
+    component: 'RangePicker',
+    componentProps: {
+      placeholder: ['开始时间', '结束时间'],
+    },
+  },
+];
+//表单数据
+export const formSchema: FormSchema[] = [
+  // TODO 主键隐藏字段,目前写死为ID
+  {
+    label: '',
+    field: 'id',
+    component: 'Input',
+    show: false,
+  },
+];
+
+/**
+ * 商品类型(1-场地 2-赛事 3-课程 4-保险)
+ */
+
+export const goodsType = [
+  { label: '学校', value: 1 },
+  { label: '包场', value: 2 },
+  { label: '无固定场', value: 3 },
+  { label: '个人赛', value: 4 },
+  { label: '团队赛', value: 5 },
+  { label: '课程', value: 6 },
+  { label: '保险', value: 7 },
+];
+
+/**
+ * 售后状态 0-暂无售后 1-待退款 1-已退款
+ */
+export const afterSaleStatus = ['暂无售后', '待退款', '已退款'];
+
+/**
+ * 0-待付款 1-待使用 2-已使用 3-已到期 4-已取消 5-退款中 6已退款
+ */
+export const orderStatus = ['待付款', '待使用', '已使用', '已到期', '已取消', '退款中', '已退款'];
+
+export const orderColum: TableColumnType[] = [
+  {
+    dataIndex: 'productName',
+    title: '商品名称',
+    align: 'center',
+    width: 280,
+  },
+  {
+    dataIndex: 'ticketNo',
+    title: '券号',
+    align: 'center',
+    width: 180,
+  },
+  {
+    dataIndex: 'originalPrice',
+    title: '原价/元',
+    align: 'center',
+    width: 180,
+    customRender: ({ record }) => {
+      return record.originalPrice || 0;
+    },
+  },
+
+  {
+    dataIndex: 'orderStatus',
+    title: '订单状态',
+    align: 'center',
+    customRender: ({ text, record }) => {
+      return record.type != 6 ? orderStatus[text] : '无';
+    },
+    width: 180,
+  },
+  {
+    dataIndex: 'quantity',
+    title: '数量',
+    align: 'center',
+    width: 180,
+  },
+  {
+    dataIndex: 'price',
+    title: '小计/元',
+    align: 'center',
+    customRender: ({ record }) => {
+      return (record.originalPrice ? record.originalPrice : 0) * record.quantity;
+    },
+    width: 180,
+  },
+];
+
+/**
+ *
+ * @param type 订单类型:0-学校 1-包场 2-无固定场 3-个人赛 4-团队赛 5-课程
+ */
+export function getColumText(type: number) {
+  let colum: TableColumnType[] = [];
+  const commonColum: TableColumnType[] = [
+    {
+      dataIndex: 'familyUserName',
+      title: '使用人',
+      align: 'center',
+      width: 180,
+    },
+    {
+      dataIndex: 'userPhone',
+      title: '手机号',
+      align: 'center',
+      width: 180,
+      customRender: ({ record }) => {
+        return record.isinList[0].userPhone;
+      },
+    },
+    {
+      dataIndex: 'isinCode',
+      title: '劵号',
+      align: 'center',
+      width: 180,
+    },
+    {
+      dataIndex: 'isinCode',
+      title: '使用地点',
+      align: 'center',
+      customRender: ({ record }) => {
+        const viewList: VNode[] = [];
+        record.isinList.forEach((it) => {
+          viewList.push(h('div', it.useAddress));
+        });
+        return h('div', viewList);
+      },
+      width: 280,
+    },
+    {
+      dataIndex: 'isinCode',
+      title: '使用时间',
+      align: 'center',
+      customRender: ({ record }) => {
+        const viewList: VNode[] = [];
+        record.isinList.forEach((it) => {
+          viewList.push(h('div', it.useTime));
+        });
+        return h('div', viewList);
+      },
+      width: 280,
+    },
+  ];
+  if (type == 0) {
+    colum = [...commonColum];
+  }
+  if (type == 1 || type == 2) {
+    //包场和无固定场显示一样的,
+    colum = [
+      {
+        dataIndex: 'isinCode',
+        title: '劵号',
+        align: 'center',
+        width: 180,
+      },
+      {
+        dataIndex: 'isinCode',
+        title: '使用地点',
+        align: 'center',
+        customRender: ({ record }) => {
+          const viewList: VNode[] = [];
+          record.isinList.forEach((it) => {
+            viewList.push(h('div', it.useAddress));
+          });
+          return h('div', viewList);
+        },
+        width: 280,
+      },
+      {
+        dataIndex: 'isinCode',
+        title: '核验人员',
+        align: 'center',
+        customRender: ({ record }) => {
+          const viewList: VNode[] = [];
+          record.isinList.forEach((it) => {
+            viewList.push(h('div', it.verifyUserName));
+          });
+          return h('div', viewList);
+        },
+      },
+      {
+        dataIndex: 'isinCode',
+        title: '使用时间',
+        align: 'center',
+        customRender: ({ record }) => {
+          const viewList: VNode[] = [];
+          record.isinList.forEach((it) => {
+            viewList.push(h('div', it.useTime));
+          });
+          return h('div', viewList);
+        },
+        width: 280,
+      },
+    ];
+  }
+  if (type == 5) {
+    colum = [...commonColum];
+    colum.splice(3, 0, {
+      dataIndex: 'isinCode',
+      title: '核验人员',
+      align: 'center',
+      customRender: ({ record }) => {
+        const viewList: VNode[] = [];
+        record.isinList.forEach((it) => {
+          viewList.push(h('div', it.verifyUserName));
+        });
+        return h('div', viewList);
+      },
+    });
+  }
+  if (type == 3 || type == 4) {
+    colum = [...commonColum];
+    colum.splice(3, 0, {
+      dataIndex: 'isinCode',
+      title: '核验人员/使用照片',
+      align: 'center',
+      width: 280,
+      customRender: ({ record }) => {
+        const viewList: VNode[] = [];
+        record.isinList.forEach((it) => {
+          viewList.push(h('div', it.verifyUserName));
+        });
+        return h('div', viewList);
+      },
+    });
+  }
+  return colum;
+}
+
+export const verificationRecordColumns: TableColumnType[] = [
+  {
+    dataIndex: 'familyUserName',
+    title: '上课时间',
+    align: 'center',
+    width: 220,
+    customRender: ({ record }) => {
+      return `${dayjs(record.coursesStartTime).format('YYYY-MM-DD HH:mm')} ${dayjs(record.coursesEndTime).format('HH:mm')}`;
+    },
+  },
+  {
+    dataIndex: 'coursesName',
+    title: '课时名称',
+    align: 'center',
+    width: 420,
+  },
+  {
+    dataIndex: 'useUserName',
+    title: '使用人',
+    align: 'center',
+    width: 180,
+  },
+  {
+    dataIndex: 'verifyStatus',
+    title: '核销状态',
+    align: 'left',
+    width: 180,
+
+    customRender: ({ text, record }) => {
+      const Viewtext = h('div', { class: 'mr2' }, text == 1 ? '已核销' : '未核销');
+      return record.orPostpone == 0 ? Viewtext : h('div', { class: 'flex items-center' }, [Viewtext, h(Tag, { color: 'green' }, () => '已延课')]);
+    },
+  },
+  {
+    dataIndex: 'verifyUserName',
+    title: '核验人',
+    align: 'center',
+    width: 180,
+  },
+  {
+    dataIndex: 'isinCode',
+    title: '核验照片',
+    align: 'center',
+    width: 180,
+
+    customRender: ({ record }) => {
+      return record.verifyImage ? h(Image, { src: record.verifyImage, width: 100, height: 100 }) : '';
+    },
+  },
+  {
+    dataIndex: 'verifyTime',
+    title: '核验时间',
+    align: 'center',
+    width: 280,
+  },
+];
+
+export const gameScheduleVOListColumns: TableColumnType[] = [
+  {
+    title: '比赛项目',
+    dataIndex: 'name',
+    align: 'center',
+  },
+  {
+    title: '时间段',
+    dataIndex: 'startTime',
+    align: 'center',
+    customRender: ({ record }) => {
+      return `${record.startTime} - ${record.endTime}`;
+    },
+  },
+  {
+    title: '安排',
+    dataIndex: 'arrange',
+    align: 'center',
+  },
+  {
+    title: '比赛状态',
+    dataIndex: 'startStatus',
+    align: 'center',
+  },
+];