Преглед изворни кода

feat(calssGroup): 新增班级分组管理功能

- 创建NmClassGroupingForm组件用于班级分组表单操作
- 创建NmClassGroupingModal组件实现分班情况弹窗管理
- 实现创建、修改、查看、删除分班功能
- 添加待分班学员选择表格和教练选择功能
- 集成caseList、studentInfoList、queryCoach等API接口
- 完成分班信息的增删改查业务逻辑

fix(userInfo): 修正用户信息搜索表单字段映射

- 将用户昵称搜索字段从merchantName改为username
- 将是否实名搜索字段从accountStatus改为realNameStatus
zouzexu пре 11 часа
родитељ
комит
b96503cd1e

+ 70 - 0
src/views/calssGroup/calssGroupInfo/components/NmClassGroupingForm.vue

@@ -0,0 +1,70 @@
+<template>
+    <div style="min-height: 400px">
+        <BasicForm @register="registerForm"></BasicForm>
+        <div style="width: 100%;text-align: center" v-if="!formDisabled">
+            <a-button @click="submitForm" pre-icon="ant-design:check" type="primary">提 交</a-button>
+        </div>
+    </div>
+</template>
+
+<script lang="ts">
+    import {BasicForm, useForm} from '/src/components/Form';
+    import {computed, defineComponent} from 'vue';
+    import {defHttp} from '/src/utils/http/axios';
+    import { propTypes } from '/src/utils/propTypes';
+    import {getBpmFormSchema} from '../NmClassGrouping.data';
+    import {saveOrUpdate} from '../NmClassGrouping.api';
+
+    export default defineComponent({
+        name: "NmClassGroupingForm",
+        components:{
+            BasicForm
+        },
+        props:{
+            formData: propTypes.object.def({}),
+            formBpm: propTypes.bool.def(true),
+        },
+        setup(props){
+            const [registerForm, { setFieldsValue, setProps, getFieldsValue }] = useForm({
+                labelWidth: 150,
+                schemas: getBpmFormSchema(props.formData),
+                showActionButtonGroup: false,
+                baseColProps: {span: 24}
+            });
+
+            const formDisabled = computed(()=>{
+                if(props.formData.disabled === false){
+                    return false;
+                }
+                return true;
+            });
+
+            let formData = {};
+            const queryByIdUrl = '/calssGroup/nmClassGrouping/queryById';
+            async function initFormData(){
+                let params = {id: props.formData.dataId};
+                const data = await defHttp.get({url: queryByIdUrl, params});
+                formData = {...data}
+                //设置表单的值
+                await setFieldsValue(formData);
+                //默认是禁用
+                await setProps({disabled: formDisabled.value})
+            }
+
+            async function submitForm() {
+                let data = getFieldsValue();
+                let params = Object.assign({}, formData, data);
+                console.log('表单数据', params)
+                await saveOrUpdate(params, true)
+            }
+
+            initFormData();
+
+            return {
+                registerForm,
+                formDisabled,
+                submitForm,
+            }
+        }
+    });
+</script>

+ 351 - 0
src/views/calssGroup/calssGroupInfo/components/NmClassGroupingModal.vue

@@ -0,0 +1,351 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose title="分班情况" width="80%" @ok="handleSubmit">
+    <BasicTable @register="registerTable">
+      <template #tableTitle>
+        <a-button type="primary" @click="createClass">创建分班</a-button>
+      </template>
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)" />
+      </template>
+    </BasicTable>
+    <a-modal :open="previewVisible" @cancel="previewVisible = false" width="65%" @ok="submitStudentInfo" :confirmLoading="submitConfirmLoading">
+      <div class="h-10"></div>
+      <div class="flex">
+        <a-form :label-col="{ span: 8 }" :wrapper-col="{ span: 16, style: { maxWidth: '500px' } }">
+          <a-form-item label="班级名称" :rules="[{ required: true, message: '请输入班级名称' }]">
+            <a-input v-model:value="formData.className" placeholder="请输入班级名称" :disabled="isDetail" />
+          </a-form-item>
+          <a-form-item label="教练" :rules="[{ required: true, message: '请选择教练' }]">
+            <a-select v-model:value="formData.coachUserId" placeholder="请选择教练" :disabled="isDetail">
+              <a-select-option v-for="coach in coachList" :key="coach.coachUserId" :value="coach.coachUserId">
+                {{ coach.name }}
+              </a-select-option>
+            </a-select>
+          </a-form-item>
+        </a-form>
+      </div>
+      <BasicTable @register="registerTableSelect" :rowSelection="rowSelection" :pagination="false">
+        <template #tableTitle>
+          <div>待分班学员</div>
+        </template>
+      </BasicTable>
+    </a-modal>
+  </BasicModal>
+</template>
+
+<script lang="ts" setup>
+  import { ref, computed, unref, watch, nextTick } from 'vue';
+  import { BasicModal, useModalInner } from '/src/components/Modal';
+  import { BasicForm, useForm } from '/src/components/Form';
+  import { caseList, saveOrUpdate, studentInfoList, queryCoach, addClass, editClass, deleteOne } from '../NmClassGrouping.api';
+  import { useMessage } from '/src/hooks/web/useMessage';
+  import { BasicTable, TableAction } from '@/components/Table';
+  import { useListPage } from '@/hooks/system/useListPage';
+  import { columns1, columns2, searchFormSchemaModal, formSchema } from '../NmClassGrouping.data';
+  import { putProfitSharing } from '@/views/orderManagement/order/order.api';
+
+  const { createMessage, createWarningModal } = useMessage();
+  // Emits声明
+  const emit = defineEmits(['register', 'success']);
+  const isUpdate = ref(false);
+  const isDetail = ref(false);
+  const previewVisible = ref(false);
+  //注册table数据
+  const { prefixCls, tableContext } = useListPage({
+    tableProps: {
+      title: '',
+      api: caseList,
+      columns: columns1,
+      formConfig: {
+        //labelWidth: 120,
+        schemas: searchFormSchemaModal,
+        autoSubmitOnEnter: true,
+        showAdvancedButton: true,
+        fieldMapToNumber: [],
+        fieldMapToTime: [],
+        autoAdvancedCol: 4,
+      },
+
+      actionColumn: {
+        width: 180,
+        fixed: 'right',
+      },
+      beforeFetch: (params) => {
+        return Object.assign(params, { courseId: currentId.value || '' });
+      },
+    },
+  });
+  const currentId = ref(null);
+  const classGroupingId = ref('');
+  const { tableContext: tableContext1 } = useListPage({
+    tableProps: {
+      title: '',
+      api: studentInfoList,
+      columns: columns2,
+      beforeFetch: (params) => {
+        if (currentId.value) {
+          return Object.assign(params, {
+            coursesId: currentId.value,
+            classGroupingId: classGroupingId.value || '',
+          });
+        }
+        return params;
+      },
+      afterFetch: (dataSource) => {
+        const defaultSelectedKeys = dataSource.filter((item) => item.orChoose).map((item) => item.id);
+
+        if (defaultSelectedKeys.length > 0) {
+          setTimeout(() => {
+            setSelectedRowKeys(defaultSelectedKeys);
+          }, 0);
+        }
+        return dataSource;
+      },
+      rowSelection: {
+        // 开启多选
+        type: 'checkbox',
+        getCheckboxProps: (record) => ({
+          disabled: isDetail.value,
+        }),
+        onChange: (selectedRowKeys, selectedRows) => {
+          formData.value.familyMemberIds = selectedRowKeys;
+          console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
+        },
+      },
+      formConfig: {
+        //labelWidth: 120,
+        autoSubmitOnEnter: false,
+        showAdvancedButton: false,
+        fieldMapToNumber: [],
+        fieldMapToTime: [],
+        autoAdvancedCol: 4,
+      },
+      actionColumn: null,
+    },
+  });
+
+  function createClass() {
+    // 重置表单数据
+    formData.value = {
+      id: '',
+      className: '',
+      courseId: '',
+      coachUserId: null,
+      familyMemberIds: null,
+    };
+    setTimeout(() => {
+      try {
+        resetFields();
+      } catch (e) {
+        console.warn('表单重置失败:', e);
+      }
+      try {
+        setSelectedRowKeys([]);
+      } catch (e) {
+        console.warn('表格选中项重置失败:', e);
+      }
+    }, 0);
+    classGroupingId.value = '';
+    isUpdate.value = false;
+    isDetail.value = false;
+    reloadEdit();
+    previewVisible.value = true;
+  }
+
+  watch(currentId, async (newId) => {
+    if (newId) {
+      try {
+        const coachRes = await queryCoach({ coursesId: newId });
+        coachList.value = coachRes;
+        await reloadEdit();
+        setTimeout(async () => {
+          const tableData = await studentInfoList({
+            coursesId: newId,
+            classGroupingId: classGroupingId.value || '',
+          });
+          const defaultSelectedKeys = tableData.filter((item) => item.orChoose).map((item) => item.id);
+          if (defaultSelectedKeys.length > 0) {
+            setSelectedRowKeys(defaultSelectedKeys);
+          }
+        }, 100);
+      } catch (error) {
+        console.error('获取数据失败:', error);
+      }
+    } else {
+      coachList.value = [];
+    }
+  });
+  const [registerTable, { reload: reloadlist }] = tableContext;
+  const [registerTableSelect, { reload: reloadEdit, setSelectedRowKeys }, { rowSelection }] = tableContext1;
+  const coachList = ref([]);
+
+  function handleDelete(record) {
+    createWarningModal({
+      title: '提示',
+      content: '删除后分班信息将不存在,已分班学员需重新进行分配!!!!',
+      okText: '确认',
+      cancelText: '取消',
+      okCancel: true,
+      onOk: () => {
+        deleteOne({ classGroupingId: record.id }, () => {
+          reloadlist();
+        });
+      },
+      onCancel: () => {
+        reloadlist();
+      },
+    });
+  }
+
+  /**
+   * 操作栏
+   */
+  function getTableAction(record) {
+    return [
+      {
+        label: '修改分班',
+        onClick: () => {
+          classGroupingId.value = record.id;
+          formData.value.className = record.classGroupingName;
+          if (record.coachName && coachList.value.length > 0) {
+            const coach = coachList.value.find((item) => item.name === record.coachName);
+            if (coach) {
+              formData.value.coachUserId = coach.coachUserId;
+            }
+          }
+          isUpdate.value = true;
+          isDetail.value = false;
+          reloadEdit();
+          previewVisible.value = true;
+        },
+      },
+      {
+        label: '查看',
+        onClick: () => {
+          classGroupingId.value = record.id;
+          formData.value.className = record.classGroupingName;
+          if (record.coachName && coachList.value.length > 0) {
+            const coach = coachList.value.find((item) => item.name === record.coachName);
+            if (coach) {
+              formData.value.coachUserId = coach.coachUserId;
+            }
+          }
+          isDetail.value = true;
+          reloadEdit();
+          previewVisible.value = true;
+        },
+      },
+      {
+        label: '删除',
+        onClick: handleDelete.bind(null, record),
+      },
+    ];
+  }
+
+  //表单配置
+  const [registerForm, { setProps, resetFields, setFieldsValue, validate, scrollToField }] = useForm({
+    labelWidth: 150,
+    schemas: formSchema,
+    showActionButtonGroup: false,
+    baseColProps: { span: 24 },
+  });
+
+  const formData = ref({
+    id: '',
+    className: '',
+    courseId: '',
+    coachUserId: null,
+    familyMemberIds: null,
+  });
+  const submitConfirmLoading = ref(false);
+  const submitStudentInfo = async () => {
+    try {
+      if (!formData.value.className) {
+        createMessage.warning('请输入班级名称');
+        return;
+      }
+      if (!formData.value.coachUserId) {
+        createMessage.warning('请选择教练');
+        return;
+      }
+      if (!formData.value.familyMemberIds || formData.value.familyMemberIds.length === 0) {
+        createMessage.warning('请选择待分班学员');
+        return;
+      }
+      submitConfirmLoading.value = true;
+      formData.value.courseId = currentId.value || '';
+      if (!isUpdate.value) {
+        await addClass(formData.value);
+      } else {
+        formData.value.id = classGroupingId.value;
+        await editClass(formData.value);
+      }
+      previewVisible.value = false;
+      await reloadlist();
+    } catch (error) {
+      console.error('提交失败:', error);
+    } finally {
+      submitConfirmLoading.value = false;
+    }
+  };
+  //表单赋值
+  const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
+    //重置表单
+    await resetFields();
+    setModalProps({
+      confirmLoading: false,
+      showCancelBtn: !!data?.showFooter,
+      showOkBtn: !!data?.showFooter,
+    });
+    isUpdate.value = !!data?.isUpdate;
+    isDetail.value = !!data?.showFooter;
+    if (data?.record?.id) {
+      currentId.value = data.record.id;
+    }
+    if (unref(isUpdate)) {
+      //表单赋值
+      await setFieldsValue({
+        ...data.record,
+      });
+    }
+    // 隐藏底部时禁用整个表单
+    setProps({ disabled: !data?.showFooter });
+  });
+  //设置标题
+  const title = computed(() => (!unref(isUpdate) ? '新增' : !unref(isDetail) ? '详情' : '编辑'));
+
+  //表单提交事件
+  async function handleSubmit(v) {
+    try {
+      let values = await validate();
+      setModalProps({ confirmLoading: true });
+      //提交表单
+      await saveOrUpdate(values, isUpdate.value);
+      //关闭弹窗
+      closeModal();
+      //刷新列表
+      emit('success');
+    } catch ({ errorFields }) {
+      if (errorFields) {
+        const firstField = errorFields[0];
+        if (firstField) {
+          scrollToField(firstField.name, { behavior: 'smooth', block: 'center' });
+        }
+      }
+      return Promise.reject(errorFields);
+    } finally {
+      setModalProps({ confirmLoading: false });
+    }
+  }
+</script>
+
+<style lang="less" scoped>
+  /** 时间和数字输入框样式 */
+  :deep(.ant-input-number) {
+    width: 100%;
+  }
+
+  :deep(.ant-calendar-picker) {
+    width: 100%;
+  }
+</style>

+ 2 - 2
src/views/informationManagement/cUserInfo/cUserInfo.data.ts

@@ -46,13 +46,13 @@ export const columns: BasicColumn[] = [
 export const searchFormSchema: FormSchema[] = [
   {
     label: '用户昵称',
-    field: 'merchantName',
+    field: 'username',
     component: 'Input',
     colProps: { span: 6 },
   },
   {
     label: '是否实名',
-    field: 'accountStatus',
+    field: 'realNameStatus',
     component: 'Select',
     colProps: { span: 6 },
     componentProps: {