src/views目录下创建demo目录(模块),并创建对应的组件:

src/views/demo/demoGenClass/index.vue:

<template>
  <div class="demo-demoGenClass-container">
    <el-card shadow="hover">
      <div class="demo-demoGenClass-search mb15">
        <el-form :model="tableData.param" ref="queryRef" :inline="true" label-width="100px">
          <el-row>
            <el-col :span="8" class="colBlock">
              <el-form-item label="分类名" prop="className">
                <el-input
                    v-model="tableData.param.className"
                    placeholder="请输入分类名"
                    clearable
                    size="small"
                    @keyup.enter.native="demoGenClassList"
                />
              </el-form-item>
            </el-col>
            <el-col :span="8" class="colBlock">
              <el-form-item>
                <el-button type="primary"  size="small" @click="demoGenClassList"><el-icon><ele-Search /></el-icon>搜索</el-button>
                <el-button size="small" @click="resetQuery(queryRef)"><el-icon><ele-Refresh /></el-icon>重置</el-button>
              </el-form-item>
            </el-col>
          </el-row>
        </el-form>
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button
                type="primary"
                size="small"
                @click="handleAdd"
                v-auth="'api/v1/demo/demoGenClass/add'"
            ><el-icon><ele-Plus /></el-icon>新增</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button
                type="success"
                size="small"
                :disabled="single"
                @click="handleUpdate(null)"
                v-auth="'api/v1/demo/demoGenClass/edit'"
            ><el-icon><ele-Edit /></el-icon>修改</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button
                type="danger"
                size="small"
                :disabled="multiple"
                @click="handleDelete(null)"
                v-auth="'api/v1/demo/demoGenClass/delete'"
            ><el-icon><ele-Delete /></el-icon>删除</el-button>
          </el-col>
        </el-row>
      </div>
      <el-table v-loading="loading" :data="tableData.data" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="分类id" align="center" prop="id"
                         min-width="100px"
        />
        <el-table-column label="分类名" align="center" prop="className"
                         min-width="100px"
        />
        <el-table-column label="操作" align="center" class-name="small-padding" min-width="200px" fixed="right">
          <template #default="scope">
            <el-button
                size="small"
                type="primary"
                link
                icon="el-icon-view"
                @click="handleView(scope.row)"
                v-auth="'api/v1/demo/demoGenClass/view'"
            >详情</el-button>
            <el-button
                size="small"
                type="primary"
                link
                icon="el-icon-edit"
                @click="handleUpdate(scope.row)"
                v-auth="'api/v1/demo/demoGenClass/edit'"
            >修改</el-button>
            <el-button
                size="small"
                type="primary"
                link
                icon="el-icon-delete"
                @click="handleDelete(scope.row)"
                v-auth="'api/v1/demo/demoGenClass/delete'"
            >删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
          v-show="tableData.total>0"
          :total="tableData.total"
          v-model:page="tableData.param.pageNum"
          v-model:limit="tableData.param.pageSize"
          @pagination="demoGenClassList"
      />
    </el-card>
    <apiV1DemoDemoGenClassEdit
        ref="editRef"
        @demoGenClassList="demoGenClassList"
    ></apiV1DemoDemoGenClassEdit>
    <apiV1DemoDemoGenClassDetail
        ref="detailRef"
        @demoGenClassList="demoGenClassList"
    ></apiV1DemoDemoGenClassDetail>
  </div>
</template>
<script lang="ts">
import {ItemOptions} from "/@/api/items";
import {toRefs, reactive, onMounted, ref, defineComponent, computed,getCurrentInstance,toRaw} from 'vue';
import {ElMessageBox, ElMessage, FormInstance} from 'element-plus';
import {
  listDemoGenClass,
  getDemoGenClass,
  delDemoGenClass,
  addDemoGenClass,
  updateDemoGenClass,
} from "/@/api/demo/demoGenClass";
import {
  DemoGenClassTableColumns,
  DemoGenClassInfoData,
  DemoGenClassTableDataState,
} from "/@/views/demo/demoGenClass/component/model"
import apiV1DemoDemoGenClassEdit from "/@/views/demo/demoGenClass/component/edit.vue"
import apiV1DemoDemoGenClassDetail from "/@/views/demo/demoGenClass/component/detail.vue"
export default defineComponent({
  name: "apiV1DemoDemoGenClassList",
  components:{
    apiV1DemoDemoGenClassEdit,
    apiV1DemoDemoGenClassDetail
  },
  setup() {
    const {proxy} = <any>getCurrentInstance()
    const loading = ref(false)
    const queryRef = ref()
    const editRef = ref();
    const detailRef = ref();
    // 是否显示所有搜索选项
    const showAll =  ref(false)
    // 非单个禁用
    const single = ref(true)
    // 非多个禁用
    const multiple =ref(true)
    const word = computed(()=>{
      if(showAll.value === false) {
        //对文字进行处理
        return "展开搜索";
      } else {
        return "收起搜索";
      }
    })
    // 字典选项数据
    const {
    } = proxy.useDict(
    )
    const state = reactive<DemoGenClassTableDataState>({
      ids:[],
      tableData: {
        data: [],
        total: 0,
        loading: false,
        param: {
          pageNum: 1,
          pageSize: 10,
          className: undefined,
        },
      },
    });
    // 页面加载时
    onMounted(() => {
      initTableData();
    });
    // 初始化表格数据
    const initTableData = () => {
      demoGenClassList()
    };
    /** 重置按钮操作 */
    const resetQuery = (formEl: FormInstance | undefined) => {
      if (!formEl) return
      formEl.resetFields()
      demoGenClassList()
    };
    // 获取列表数据
    const demoGenClassList = ()=>{
      loading.value = true
      listDemoGenClass(state.tableData.param).then((res:any)=>{
        let list = res.data.list??[];
        state.tableData.data = list;
        state.tableData.total = res.data.total;
        loading.value = false
      })
    };
    const toggleSearch = () => {
      showAll.value = !showAll.value;
    }
    // 多选框选中数据
    const handleSelectionChange = (selection:Array<DemoGenClassInfoData>) => {
      state.id = selection.map(item => item.id)
      single.value = selection.length!=1
      multiple.value = !selection.length
    }
    const handleAdd =  ()=>{
      editRef.value.openDialog()
    }
    const handleUpdate = (row: DemoGenClassTableColumns) => {
      if(!row){
        row = state.tableData.data.find((item:DemoGenClassTableColumns)=>{
          return item.id ===state.id[0]
        }) as DemoGenClassTableColumns
      }
      editRef.value.openDialog(toRaw(row));
    };
    const handleDelete = (row: DemoGenClassTableColumns) => {
      let msg = '你确定要删除所选数据?';
      let id:number[] = [] ;
      if(row){
        msg = `此操作将永久删除数据,是否继续?`
        id = [row.id]
      }else{
        id = state.id
      }
      if(id.length===0){
        ElMessage.error('请选择要删除的数据。');
        return
      }
      ElMessageBox.confirm(msg, '提示', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      })
          .then(() => {
            delDemoGenClass(id).then(()=>{
              ElMessage.success('删除成功');
              demoGenClassList();
            })
          })
          .catch(() => {});
    }
    const handleView = (row:DemoGenClassTableColumns)=>{
      detailRef.value.openDialog(toRaw(row));
    }
    return {
      proxy,
      editRef,
      detailRef,
      showAll,
      loading,
      single,
      multiple,
      word,
      queryRef,
      resetQuery,
      demoGenClassList,
      toggleSearch,
      handleSelectionChange,
      handleAdd,
      handleUpdate,
      handleDelete,
      handleView,
      ...toRefs(state),
    }
  }
})
</script>
<style lang="scss" scoped>
.colBlock {
  display: block;
}
.colNone {
  display: none;
}
</style>

src/views/demo/demoGenClass/component/model.ts:

export interface DemoGenClassTableColumns {
    id:number;  // 分类id
    className:string;  // 分类名
}


export interface DemoGenClassInfoData {
    id:number|undefined;        // 分类id
    className:string|undefined; // 分类名
}


export interface DemoGenClassTableDataState {
    ids:any[];
    tableData: {
        data: Array<DemoGenClassTableColumns>;
        total: number;
        loading: boolean;
        param: {
            pageNum: number;
            pageSize: number;
            className: string|undefined;
        };
    };
}


export interface DemoGenClassEditState{
    loading:boolean;
    isShowDialog: boolean;
    formData:DemoGenClassInfoData;
    rules: object;
}

src/views/demo/demoGenClass/component/edit.vue:

<template>
  <div class="demo-demoGenClass-edit">
    <!-- 添加或修改分类信息对话框 -->
    <el-dialog v-model="isShowDialog" width="769px" :close-on-click-modal="false" :destroy-on-close="true">
      <template #header>
        <div v-drag="['.demo-demoGenClass-edit .el-dialog', '.demo-demoGenClass-edit .el-dialog__header']">{{(!formData.id || formData.id==0?'添加':'修改')+'分类信息'}}</div>
      </template>
      <el-form ref="formRef" :model="formData" :rules="rules" size="default" label-width="90px">
        <el-form-item label="分类名" prop="className">
          <el-input v-model="formData.className" placeholder="请输入分类名" />
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="onSubmit">确 定</el-button>
          <el-button @click="onCancel">取 消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script lang="ts">
import { reactive, toRefs, defineComponent,ref,unref,getCurrentInstance } from 'vue';
import {ElMessageBox, ElMessage, FormInstance,UploadProps} from 'element-plus';
import {
  listDemoGenClass,
  getDemoGenClass,
  delDemoGenClass,
  addDemoGenClass,
  updateDemoGenClass,
} from "/@/api/demo/demoGenClass";
import {
  DemoGenClassTableColumns,
  DemoGenClassInfoData,
  DemoGenClassTableDataState,
  DemoGenClassEditState,
} from "/@/views/demo/demoGenClass/list/component/model"
export default defineComponent({
  name:"apiV1DemoDemoGenClassEdit",
  components:{
  },
  props:{
  },
  setup(props,{emit}) {
    const {proxy} = <any>getCurrentInstance()
    const formRef = ref<HTMLElement | null>(null);
    const menuRef = ref();
    const state = reactive<DemoGenClassEditState>({
      loading:false,
      isShowDialog: false,
      formData: {
        id: undefined,
        className: undefined,
      },
      // 表单校验
      rules: {
        id : [
          { required: true, message: "分类id不能为空", trigger: "blur" }
        ],
        className : [
          { required: true, message: "分类名不能为空", trigger: "blur" }
        ],
      }
    });
    // 打开弹窗
    const openDialog = (row?: DemoGenClassInfoData) => {
      resetForm();
      if(row) {
        getDemoGenClass(row.id!).then((res:any)=>{
          const data = res.data;
          state.formData = data;
        })
      }
      state.isShowDialog = true;
    };
    // 关闭弹窗
    const closeDialog = () => {
      state.isShowDialog = false;
    };
    // 取消
    const onCancel = () => {
      closeDialog();
    };
    // 提交
    const onSubmit = () => {
      const formWrap = unref(formRef) as any;
      if (!formWrap) return;
      formWrap.validate((valid: boolean) => {
        if (valid) {
          state.loading = true;
          if(!state.formData.id || state.formData.id===0){
            //添加
            addDemoGenClass(state.formData).then(()=>{
              ElMessage.success('添加成功');
              closeDialog(); // 关闭弹窗
              emit('demoGenClassList')
            }).finally(()=>{
              state.loading = false;
            })
          }else{
            //修改
            updateDemoGenClass(state.formData).then(()=>{
              ElMessage.success('修改成功');
              closeDialog(); // 关闭弹窗
              emit('demoGenClassList')
            }).finally(()=>{
              state.loading = false;
            })
          }
        }
      });
    };
    const resetForm = ()=>{
      state.formData = {
        id: undefined,
        className: undefined,
      }
    };
    return {
      proxy,
      openDialog,
      closeDialog,
      onCancel,
      onSubmit,
      menuRef,
      formRef,
      ...toRefs(state),
    };
  }
})
</script>
<style scoped>
</style>

src/views/demo/demoGenClass/component/detail.vue:

<template>
  <!-- 分类信息详情抽屉 -->  
  <div class="demo-demoGenClass-detail">
    <el-drawer v-model="isShowDialog" size="80%" direction="ltr">
      <template #header>
        <h4>分类信息详情</h4>
      </template>
      <el-form ref="formRef" :model="formData" label-width="100px">          
        <el-row>        
          <el-col :span="12">          
            <el-form-item label="分类id">{{ formData.id }}</el-form-item>          
          </el-col>        
          <el-col :span="12">          
            <el-form-item label="分类名">{{ formData.className }}</el-form-item>          
          </el-col>      
        </el-row>      
      </el-form>
    </el-drawer>
  </div>
</template>
<script lang="ts">
  import { reactive, toRefs, defineComponent,ref,unref,getCurrentInstance,computed } from 'vue';
  import {ElMessageBox, ElMessage, FormInstance,UploadProps} from 'element-plus';  
  import {
    listDemoGenClass,
    getDemoGenClass,
    delDemoGenClass,
    addDemoGenClass,
    updateDemoGenClass,    
  } from "/@/api/demo/demoGenClass";  
  import {
    DemoGenClassTableColumns,
    DemoGenClassInfoData,
    DemoGenClassTableDataState,
    DemoGenClassEditState,    
  } from "/@/views/demo/demoGenClass/list/component/model"
  export default defineComponent({
    name:"apiV1DemoDemoGenClassDetail",
    components:{      
    },
    props:{      
    },
    setup(props,{emit}) {      
      const {proxy} = <any>getCurrentInstance()
      const formRef = ref<HTMLElement | null>(null);
      const menuRef = ref();      
      const state = reactive<DemoGenClassEditState>({
        loading:false,
        isShowDialog: false,
        formData: {          
          id: undefined,          
          className: undefined,          
        },
        // 表单校验
        rules: {          
          id : [
              { required: true, message: "分类id不能为空", trigger: "blur" }
          ],          
          className : [
              { required: true, message: "分类名不能为空", trigger: "blur" }
          ],          
        }
      });
        // 打开弹窗
        const openDialog = (row?: DemoGenClassInfoData) => {
          resetForm();
          if(row) {
            getDemoGenClass(row.id!).then((res:any)=>{
              const data = res.data;              
              state.formData = data;              
            })
          }
          state.isShowDialog = true;
        };
        // 关闭弹窗
        const closeDialog = () => {
          state.isShowDialog = false;
        };
        // 取消
        const onCancel = () => {
          closeDialog();
        };
        const resetForm = ()=>{
          state.formData = {            
            id: undefined,            
            className: undefined,            
          }
        };        
        return {
          proxy,
          openDialog,
          closeDialog,
          onCancel,
          menuRef,
          formRef,          
          ...toRefs(state),
        };
      }
  })
</script>
<style scoped>  
  .demo-demoGenClass-detail :deep(.el-form-item--large .el-form-item__label){
    font-weight: bolder;
  }
  .pic-block{
    margin-right: 8px;
  }
  .file-block{
    width: 100%;
    border: 1px solid var(--el-border-color);
    border-radius: 6px;
    cursor: pointer;
    position: relative;
    overflow: hidden;
    transition: var(--el-transition-duration-fast);
    margin-bottom: 5px;
    padding: 3px 6px;
  }
  .ml-2{margin-right: 5px;}
</style>

src/views/demo/demoGen/index.vue:

<template>
  <div class="demo-demoGen-container">
    <el-card shadow="hover">
      <div class="demo-demoGen-search mb15">
        <el-form :model="tableData.param" ref="queryRef" :inline="true" label-width="100px">
          <el-row>
            <el-col :span="8" class="colBlock">
              <el-form-item label="姓名" prop="demoName">
                <el-input
                    v-model="tableData.param.demoName"
                    placeholder="请输入姓名"
                    clearable
                    size="small"
                    @keyup.enter.native="demoGenList"
                />
              </el-form-item>
            </el-col>
            <el-col :span="8" class="colBlock">
              <el-form-item label="年龄" prop="demoAge">
                <el-input
                    v-model="tableData.param.demoAge"
                    placeholder="请输入年龄"
                    clearable
                    size="small"
                    @keyup.enter.native="demoGenList"
                />
              </el-form-item>
            </el-col>
            <el-col :span="8" :class="!showAll ? 'colBlock' : 'colNone'">
              <el-form-item>
                <el-button type="primary" size="small" @click="demoGenList"><el-icon><ele-Search /></el-icon>搜索</el-button>
                <el-button size="small" @click="resetQuery(queryRef)"><el-icon><ele-Refresh /></el-icon>重置</el-button>
                <el-button type="primary" link size="small" @click="toggleSearch">
                  {{ word }}
                  <el-icon v-show="showAll"><ele-ArrowUp/></el-icon>
                  <el-icon v-show="!showAll"><ele-ArrowDown /></el-icon>
                </el-button>
              </el-form-item>
            </el-col>
            <el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
              <el-form-item label="班级" prop="classes">
                <el-select v-model="tableData.param.classes" placeholder="请选择班级" clearable size="small"  @click.native="getDemoGenClassItemsClasses">
                  <el-option
                      v-for="item in classesOptions"
                      :key="item.key"
                      :label="item.value"
                      :value="item.key"
                  />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
              <el-form-item label="班级2" prop="classesTwo">
                <el-select v-model="tableData.param.classesTwo" placeholder="请选择班级2" clearable size="small"  @click.native="getDemoGenClassItemsClassesTwo">
                  <el-option
                      v-for="item in classesTwoOptions"
                      :key="item.key"
                      :label="item.value"
                      :value="item.key"
                  />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
              <el-form-item label="出生年月" prop="demoBorn">
                <el-date-picker
                    clearable size="small" style="width: 200px"
                    v-model="tableData.param.demoBorn"
                    type="datetime"
                    placeholder="选择出生年月"
                ></el-date-picker>
              </el-form-item>
            </el-col>
            <el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
              <el-form-item label="性别" prop="demoGender">
                <el-select v-model="tableData.param.demoGender" placeholder="请选择性别" clearable size="small">
                  <el-option
                      v-for="dict in sys_user_sex"
                      :key="dict.value"
                      :label="dict.label"
                      :value="dict.value"
                  />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
              <el-form-item label="状态" prop="demoStatus">
                <el-select v-model="tableData.param.demoStatus" placeholder="请选择状态" clearable size="small">
                  <el-option
                      v-for="dict in sys_normal_disable"
                      :key="dict.value"
                      :label="dict.label"
                      :value="dict.value"
                  />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
              <el-form-item label="分类" prop="demoCate">
                <el-select v-model="tableData.param.demoCate" placeholder="请选择分类" clearable size="small">
                  <el-option
                      v-for="dict in sys_oper_log_status"
                      :key="dict.value"
                      :label="dict.label"
                      :value="dict.value"
                  />
                </el-select>
              </el-form-item>
            </el-col>
            <el-col :span="8" :class="showAll ? 'colBlock' : 'colNone'">
              <el-form-item>
                <el-button type="primary" size="small" @click="demoGenList"><el-icon><ele-Search /></el-icon>搜索</el-button>
                <el-button size="small" @click="resetQuery(queryRef)"><el-icon><ele-Refresh /></el-icon>重置</el-button>
                <el-button type="primary" link size="small" @click="toggleSearch">
                  {{ word }}
                  <el-icon v-show="showAll"><ele-ArrowUp/></el-icon>
                  <el-icon v-show="!showAll"><ele-ArrowDown /></el-icon>
                </el-button>
              </el-form-item>
            </el-col>
          </el-row>
        </el-form>
        <el-row :gutter="10" class="mb8">
          <el-col :span="1.5">
            <el-button
                type="primary"
                size="small"
                @click="handleAdd"
                v-auth="'api/v1/demo/demoGen/add'"
            ><el-icon><ele-Plus /></el-icon>新增</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button
                type="success"
                size="small"
                :disabled="single"
                @click="handleUpdate(null)"
                v-auth="'api/v1/demo/demoGen/edit'"
            ><el-icon><ele-Edit /></el-icon>修改</el-button>
          </el-col>
          <el-col :span="1.5">
            <el-button
                type="danger"
                size="small"
                :disabled="multiple"
                @click="handleDelete(null)"
                v-auth="'api/v1/demo/demoGen/delete'"
            ><el-icon><ele-Delete /></el-icon>删除</el-button>
          </el-col>
        </el-row>
      </div>
      <el-table v-loading="loading" :data="tableData.data" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="55" align="center" />
        <el-table-column label="ID" align="center" prop="id"
                         min-width="100px"
        />
        <el-table-column label="姓名" align="center" prop="demoName"
                         min-width="100px"
        />
        <el-table-column label="年龄" align="center" prop="demoAge"
                         min-width="100px"
        />
        <el-table-column label="班级" align="center" prop="linkedClasses.className"
                         min-width="100px"
        />
        <el-table-column label="班级2" align="center" prop="linkedClassesTwo.className"
                         min-width="100px"
        />
        <el-table-column label="出生年月" align="center" prop="demoBorn"
                         min-width="100px"
        >
          <template #default="scope">
            <span>{{ proxy.parseTime(scope.row.demoBorn, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
          </template>
        </el-table-column>
        <el-table-column label="性别" align="center" prop="demoGender" :formatter="demoGenderFormat"
                         min-width="100px"
        />
        <el-table-column label="创建日期" align="center" prop="createdAt"
                         min-width="100px"
        >
          <template #default="scope">
            <span>{{ proxy.parseTime(scope.row.createdAt, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
          </template>
        </el-table-column>
        <el-table-column label="创建人" align="center" prop="createdBy"
                         min-width="100px"
        />
        <el-table-column label="状态" align="center" prop="demoStatus" :formatter="demoStatusFormat"
                         min-width="100px"
        />
        <el-table-column label="分类" align="center" prop="demoCate" :formatter="demoCateFormat"
                         min-width="100px"
        />
        <el-table-column align="center" label="头像"
                         min-width="100px"
        >
          <template #default="scope">
            <el-image
                style="width: 100px; height: 50px"
                v-if="!proxy.isEmpty(scope.row.demoThumb)"
                :src="proxy.getUpFileUrl(scope.row.demoThumb)"
                fit="contain"></el-image>
          </template>
        </el-table-column>
        <el-table-column label="操作" align="center" class-name="small-padding" min-width="200px" fixed="right">
          <template #default="scope">
            <el-button
                size="small"
                type="primary"
                link
                icon="el-icon-view"
                @click="handleView(scope.row)"
                v-auth="'api/v1/demo/demoGen/view'"
            >详情</el-button>
            <el-button
                size="small"
                type="primary"
                link
                icon="el-icon-edit"
                @click="handleUpdate(scope.row)"
                v-auth="'api/v1/demo/demoGen/edit'"
            >修改</el-button>
            <el-button
                size="small"
                type="primary"
                link
                icon="el-icon-delete"
                @click="handleDelete(scope.row)"
                v-auth="'api/v1/demo/demoGen/delete'"
            >删除</el-button>
          </template>
        </el-table-column>
      </el-table>
      <pagination
          v-show="tableData.total>0"
          :total="tableData.total"
          v-model:page="tableData.param.pageNum"
          v-model:limit="tableData.param.pageSize"
          @pagination="demoGenList"
      />
    </el-card>
    <apiV1DemoDemoGenEdit
        ref="editRef"
        :classesOptions="classesOptions"
        @getDemoGenClassItemsClasses="getDemoGenClassItemsClasses"
        :classesTwoOptions="classesTwoOptions"
        @getDemoGenClassItemsClassesTwo="getDemoGenClassItemsClassesTwo"
        :demoGenderOptions="sys_user_sex"
        :demoStatusOptions="sys_normal_disable"
        :demoCateOptions="sys_oper_log_status"
        @demoGenList="demoGenList"
    ></apiV1DemoDemoGenEdit>
    <apiV1DemoDemoGenDetail
        ref="detailRef"
        :classesOptions="classesOptions"
        @getDemoGenClassItemsClasses="getDemoGenClassItemsClasses"
        :classesTwoOptions="classesTwoOptions"
        @getDemoGenClassItemsClassesTwo="getDemoGenClassItemsClassesTwo"
        :demoGenderOptions="sys_user_sex"
        :demoStatusOptions="sys_normal_disable"
        :demoCateOptions="sys_oper_log_status"
        @demoGenList="demoGenList"
    ></apiV1DemoDemoGenDetail>
  </div>
</template>
<script lang="ts">
import {ItemOptions} from "/@/api/items";
import {toRefs, reactive, onMounted, ref, defineComponent, computed,getCurrentInstance,toRaw} from 'vue';
import {ElMessageBox, ElMessage, FormInstance} from 'element-plus';
import {
  listDemoGen,
  getDemoGen,
  delDemoGen,
  addDemoGen,
  updateDemoGen,
  listDemoGenClass,
  getUserList,
} from "/@/api/demo/demoGen";
import {
  DemoGenTableColumns,
  DemoGenInfoData,
  DemoGenTableDataState,
  LinkedDemoGenDemoGenClass,
} from "/@/views/demo/demoGen/component/model"
import apiV1DemoDemoGenEdit from "/@/views/demo/demoGen/component/edit.vue"
import apiV1DemoDemoGenDetail from "/@/views/demo/demoGen/component/detail.vue"
export default defineComponent({
  name: "apiV1DemoDemoGenList",
  components:{
    apiV1DemoDemoGenEdit,
    apiV1DemoDemoGenDetail
  },
  setup() {
    const {proxy} = <any>getCurrentInstance()
    const loading = ref(false)
    const queryRef = ref()
    const editRef = ref();
    const detailRef = ref();
    // 是否显示所有搜索选项
    const showAll =  ref(false)
    // 非单个禁用
    const single = ref(true)
    // 非多个禁用
    const multiple =ref(true)
    const word = computed(()=>{
      if(showAll.value === false) {
        //对文字进行处理
        return "展开搜索";
      } else {
        return "收起搜索";
      }
    })
    // 字典选项数据
    const {
      sys_user_sex,
      sys_normal_disable,
      sys_oper_log_status,
    } = proxy.useDict(
        'sys_user_sex',
        'sys_normal_disable',
        'sys_oper_log_status',
    )
    // classesOptions关联表数据
    const classesOptions = ref<Array<ItemOptions>>([])
    // classesTwoOptions关联表数据
    const classesTwoOptions = ref<Array<ItemOptions>>([])
    const state = reactive<DemoGenTableDataState>({
      ids:[],
      tableData: {
        data: [],
        total: 0,
        loading: false,
        param: {
          pageNum: 1,
          pageSize: 10,
          demoName: undefined,
          demoAge: undefined,
          classes: undefined,
          classesTwo: undefined,
          demoBorn: undefined,
          demoGender: undefined,
          demoStatus: undefined,
          demoCate: undefined,
        },
      },
    });
    // 页面加载时
    onMounted(() => {
      initTableData();
    });
    // 初始化表格数据
    const initTableData = () => {
      demoGenList()
    };
    /** 重置按钮操作 */
    const resetQuery = (formEl: FormInstance | undefined) => {
      if (!formEl) return
      formEl.resetFields()
      demoGenList()
    };
    // 获取列表数据
    const demoGenList = ()=>{
      loading.value = true
      listDemoGen(state.tableData.param).then((res:any)=>{
        let list = res.data.list??[];
        let listUid = [];
        listUid = list.map((item:any)=>{
          return item.createdBy
        });
        getUserList(listUid).then((response:any) =>{
          let users = response.data.list||[]
          list.map((item:any)=>{
            users.forEach((user:any)=>{
              if(item.createdBy==user.id){
                item.createdBy = user.userNickname
              }
            })
          })
          state.tableData.data = list;
        })
        state.tableData.total = res.data.total;
        loading.value = false
      })
    };
    const toggleSearch = () => {
      showAll.value = !showAll.value;
    }
    //关联demo_gen_class表选项
    const getDemoGenClassItemsClasses = () => {
      if (classesOptions.value && classesOptions.value.length > 0) {
        return
      }
      proxy.getItems(listDemoGenClass, {pageSize:10000}).then((res:any) => {
        classesOptions.value = proxy.setItems(res, 'id', 'className')
      })
    }
    //关联demo_gen_class表选项
    const getDemoGenClassItemsClassesTwo = () => {
      if (classesTwoOptions.value && classesTwoOptions.value.length > 0) {
        return
      }
      proxy.getItems(listDemoGenClass, {pageSize:10000}).then((res:any) => {
        classesTwoOptions.value = proxy.setItems(res, 'id', 'className')
      })
    }
    // 性别字典翻译
    const demoGenderFormat = (row:DemoGenTableColumns) => {
      return proxy.selectDictLabel(sys_user_sex.value, row.demoGender);
    }
    // 状态字典翻译
    const demoStatusFormat = (row:DemoGenTableColumns) => {
      return proxy.selectDictLabel(sys_normal_disable.value, row.demoStatus);
    }
    // 分类字典翻译
    const demoCateFormat = (row:DemoGenTableColumns) => {
      let demoCate = row.demoCate.split(",")
      let data:Array<string> = [];
      demoCate.map(item=>{
        data.push(proxy.selectDictLabel(sys_oper_log_status.value, item))
      })
      return data.join(",")
    }
    // 多选框选中数据
    const handleSelectionChange = (selection:Array<DemoGenInfoData>) => {
      state.id = selection.map(item => item.id)
      single.value = selection.length!=1
      multiple.value = !selection.length
    }
    const handleAdd =  ()=>{
      editRef.value.openDialog()
    }
    const handleUpdate = (row: DemoGenTableColumns) => {
      if(!row){
        row = state.tableData.data.find((item:DemoGenTableColumns)=>{
          return item.id ===state.id[0]
        }) as DemoGenTableColumns
      }
      editRef.value.openDialog(toRaw(row));
    };
    const handleDelete = (row: DemoGenTableColumns) => {
      let msg = '你确定要删除所选数据?';
      let id:number[] = [] ;
      if(row){
        msg = `此操作将永久删除数据,是否继续?`
        id = [row.id]
      }else{
        id = state.id
      }
      if(id.length===0){
        ElMessage.error('请选择要删除的数据。');
        return
      }
      ElMessageBox.confirm(msg, '提示', {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      })
          .then(() => {
            delDemoGen(id).then(()=>{
              ElMessage.success('删除成功');
              demoGenList();
            })
          })
          .catch(() => {});
    }
    const handleView = (row:DemoGenTableColumns)=>{
      detailRef.value.openDialog(toRaw(row));
    }
    return {
      proxy,
      editRef,
      detailRef,
      showAll,
      loading,
      single,
      multiple,
      word,
      queryRef,
      resetQuery,
      demoGenList,
      toggleSearch,
      //关联表数据选项
      classesOptions,
      //关联demo_gen_class表选项获取数据方法
      getDemoGenClassItemsClasses,
      //关联表数据选项
      classesTwoOptions,
      //关联demo_gen_class表选项获取数据方法
      getDemoGenClassItemsClassesTwo,
      demoGenderFormat,
      sys_user_sex,
      demoStatusFormat,
      sys_normal_disable,
      demoCateFormat,
      sys_oper_log_status,
      handleSelectionChange,
      handleAdd,
      handleUpdate,
      handleDelete,
      handleView,
      ...toRefs(state),
    }
  }
})
</script>
<style lang="scss" scoped>
.colBlock {
  display: block;
}
.colNone {
  display: none;
}
</style>

src/views/demo/demoGen/component/model.ts:

export interface DemoGenTableColumns {
    id:number;  // ID
    demoName:string;  // 姓名
    demoAge:number;  // 年龄
    classes:string;  // 班级
    classesTwo:string;  // 班级2
    demoBorn:string;  // 出生年月
    demoGender:number;  // 性别
    createdAt:string;  // 创建日期
    createdBy:string;  // 创建人
    demoStatus:number;  // 状态
    demoCate:string;  // 分类
    demoThumb:string;  // 头像
    linkedDemoGenDemoGenClass:LinkedDemoGenDemoGenClass;
}


export interface DemoGenInfoData {
    id:number|undefined;        // ID
    demoName:string|undefined; // 姓名
    demoAge:number|undefined; // 年龄
    classes:string|undefined; // 班级
    classesTwo:string|undefined; // 班级2
    demoBorn:string|undefined; // 出生年月
    demoGender:boolean; // 性别
    createdAt:string|undefined; // 创建日期
    updatedAt:string|undefined; // 修改日期
    deletedAt:string|undefined; // 删除日期
    createdBy:number|undefined; // 创建人
    updatedBy:number|undefined; // 修改人
    demoStatus:boolean; // 状态
    demoCate:any[]; // 分类
    demoThumb:string|undefined; // 头像
    demoPhoto:any[]; // 相册
    demoInfo:string|undefined; // 个人描述
    demoFile:any[]; // 相关附件
    linkedDemoGenDemoGenClass:LinkedDemoGenDemoGenClass;
}


export interface LinkedDemoGenDemoGenClass {
    id:number|undefined;    // 分类id
    className:string|undefined;    // 分类名
}


export interface DemoGenTableDataState {
    ids:any[];
    tableData: {
        data: Array<DemoGenTableColumns>;
        total: number;
        loading: boolean;
        param: {
            pageNum: number;
            pageSize: number;
            demoName: string|undefined;
            demoAge: number|undefined;
            classes: string|undefined;
            classesTwo: string|undefined;
            demoBorn: string|undefined;
            demoGender: number|undefined;
            demoStatus: number|undefined;
            demoCate: string|undefined;
        };
    };
}


export interface DemoGenEditState{
    loading:boolean;
    isShowDialog: boolean;
    formData:DemoGenInfoData;
    rules: object;
}

src/views/demo/demoGen/component/edit.vue:

<template>
  <div class="demo-demoGen-edit">
    <!-- 添加或修改代码生成测试对话框 -->
    <el-dialog v-model="isShowDialog" width="769px" :close-on-click-modal="false" :destroy-on-close="true">
      <template #header>
        <div v-drag="['.demo-demoGen-edit .el-dialog', '.demo-demoGen-edit .el-dialog__header']">{{(!formData.id || formData.id==0?'添加':'修改')+'代码生成测试'}}</div>
      </template>
      <el-form ref="formRef" :model="formData" :rules="rules" size="default" label-width="90px">
        <el-form-item label="姓名" prop="demoName">
          <el-input v-model="formData.demoName" placeholder="请输入姓名" />
        </el-form-item>
        <el-form-item label="年龄" prop="demoAge">
          <el-input v-model="formData.demoAge" placeholder="请输入年龄" />
        </el-form-item>
        <el-form-item label="班级" prop="classes">
          <el-select v-model="formData.classes" placeholder="请选择班级"   @click.native="getDemoGenClassItemsClasses">
            <el-option
                v-for="item in classesOptions"
                :key="item.key"
                :label="item.value"
                :value="item.key"
            ></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="班级2" prop="classesTwo">
          <el-select v-model="formData.classesTwo" placeholder="请选择班级2"   @click.native="getDemoGenClassItemsClassesTwo">
            <el-option
                v-for="item in classesTwoOptions"
                :key="item.key"
                :label="item.value"
                :value="item.key"
            ></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="出生年月" prop="demoBorn">
          <el-date-picker clearable size="small" style="width: 200px"
                          v-model="formData.demoBorn"
                          type="datetime"
                          placeholder="选择出生年月">
          </el-date-picker>
        </el-form-item>
        <el-form-item label="性别" prop="demoGender">
          <el-radio-group v-model="formData.demoGender">
            <el-radio
                v-for="dict in demoGenderOptions"
                :key="dict.value"
                :label="dict.value"
            >{{dict.label }}</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="状态" prop="demoStatus">
          <el-radio-group v-model="formData.demoStatus">
            <el-radio
                v-for="dict in demoStatusOptions"
                :key="dict.value"
                :label="dict.value"
            >{{dict.label }}</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="分类" prop="demoCate">
          <el-checkbox-group v-model="formData.demoCate">
            <el-checkbox
                v-for="dict in demoCateOptions"
                :key="dict.value"
                :label="dict.value"
            >{{dict.label }}</el-checkbox>
          </el-checkbox-group>
        </el-form-item>
        <el-form-item label="头像" prop="demoThumb">
          <el-upload
              v-loading="upLoadingDemoThumb"
              :action="baseURL+'api/v1/system/upload/singleImg'"
              :before-upload="beforeAvatarUploadDemoThumb"
              :data="setUpData()"
              :on-success="handleAvatarSuccessDemoThumb"
              :show-file-list="false"
              class="avatar-uploader"
              name="file"
          >
            <img v-if="!proxy.isEmpty(imageUrlDemoThumb)" :src="imageUrlDemoThumb" class="avatar">
            <el-icon v-else class="avatar-uploader-icon"><ele-Plus /></el-icon>
          </el-upload>
        </el-form-item>
        <el-form-item label="相册" prop="demoPhoto" >
          <upload-img :action="baseURL+'api/v1/system/upload/singleImg'" v-model="formData.demoPhoto" @uploadData="setUpImgListDemoPhoto" :limit="10"></upload-img>
        </el-form-item>
        <el-form-item label="个人描述">
          <gf-ueditor editorId="ueDemoGenDemoInfo" v-model="formData.demoInfo" @setEditContent="setDemoInfoEditContent"></gf-ueditor>
        </el-form-item>
        <el-form-item label="相关附件" prop="demoFile" >
          <upload-file :action="baseURL+'api/v1/system/upload/singleFile'" v-model="formData.demoFile" @upFileData="setUpFileListDemoFile" :limit="10"></upload-file>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="onSubmit">确 定</el-button>
          <el-button @click="onCancel">取 消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>
<script lang="ts">
import { reactive, toRefs, defineComponent,ref,unref,getCurrentInstance } from 'vue';
import {ElMessageBox, ElMessage, FormInstance,UploadProps} from 'element-plus';
import {
  listDemoGen,
  getDemoGen,
  delDemoGen,
  addDemoGen,
  updateDemoGen,
  listDemoGenClass,
  getUserList,
} from "/@/api/demo/demoGen";
import GfUeditor from "/@/components/ueditor/index.vue"
import {getToken} from "/@/utils/gfast"
import uploadImg from "/@/components/uploadImg/index.vue"
import uploadFile from "/@/components/uploadFile/index.vue"
import {
  DemoGenTableColumns,
  DemoGenInfoData,
  DemoGenTableDataState,
  DemoGenEditState,
  LinkedDemoGenDemoGenClass,
} from "/@/views/demo/demoGen/list/component/model"
export default defineComponent({
  name:"apiV1DemoDemoGenEdit",
  components:{
    GfUeditor,
    uploadImg,
    uploadFile,
  },
  props:{
    classesOptions:{
      type:Array,
      default:()=>[]
    },
    classesTwoOptions:{
      type:Array,
      default:()=>[]
    },
    demoGenderOptions:{
      type:Array,
      default:()=>[]
    },
    demoStatusOptions:{
      type:Array,
      default:()=>[]
    },
    demoCateOptions:{
      type:Array,
      default:()=>[]
    },
  },
  setup(props,{emit}) {
    const baseURL:string|undefined|boolean = import.meta.env.VITE_API_URL
    const {proxy} = <any>getCurrentInstance()
    const formRef = ref<HTMLElement | null>(null);
    const menuRef = ref();
    //图片上传地址
    const imageUrlDemoThumb = ref('')
    //上传加载
    const upLoadingDemoThumb = ref(false)
    const state = reactive<DemoGenEditState>({
      loading:false,
      isShowDialog: false,
      formData: {
        id: undefined,
        demoName: undefined,
        demoAge: undefined,
        classes: undefined,
        classesTwo: undefined,
        demoBorn: undefined,
        demoGender: false ,
        createdAt: undefined,
        updatedAt: undefined,
        deletedAt: undefined,
        createdBy: undefined,
        updatedBy: undefined,
        demoStatus: false ,
        demoCate: [] ,
        demoThumb: undefined,
        demoPhoto: [] ,
        demoInfo: undefined,
        demoFile: [] ,
        linkedDemoGenDemoGenClass: {
          id:undefined,    // 分类id
          className:undefined,    // 分类名
        },
      },
      // 表单校验
      rules: {
        id : [
          { required: true, message: "ID不能为空", trigger: "blur" }
        ],
        demoName : [
          { required: true, message: "姓名不能为空", trigger: "blur" }
        ],
        demoStatus : [
          { required: true, message: "状态不能为空", trigger: "blur" }
        ],
      }
    });
    // 打开弹窗
    const openDialog = (row?: DemoGenInfoData) => {
      resetForm();
      if(row) {
        getDemoGenClassItemsClasses()
        getDemoGenClassItemsClassesTwo()
        getDemoGen(row.id!).then((res:any)=>{
          const data = res.data;
          data.demoGender = ''+data.demoGender
          data.demoStatus = ''+data.demoStatus
          data.demoCate = data.demoCate.split(",")
          //单图地址赋值
          imageUrlDemoThumb.value = data.demoThumb ? proxy.getUpFileUrl(data.demoThumb) : ''
          data.demoPhoto =data.demoPhoto?JSON.parse(data.demoPhoto) : []
          data.demoFile =data.demoFile?JSON.parse(data.demoFile) : []
          state.formData = data;
        })
      }
      state.isShowDialog = true;
    };
    // 关闭弹窗
    const closeDialog = () => {
      state.isShowDialog = false;
    };
    // 取消
    const onCancel = () => {
      closeDialog();
    };
    // 提交
    const onSubmit = () => {
      const formWrap = unref(formRef) as any;
      if (!formWrap) return;
      formWrap.validate((valid: boolean) => {
        if (valid) {
          state.loading = true;
          if(!state.formData.id || state.formData.id===0){
            //添加
            addDemoGen(state.formData).then(()=>{
              ElMessage.success('添加成功');
              closeDialog(); // 关闭弹窗
              emit('demoGenList')
            }).finally(()=>{
              state.loading = false;
            })
          }else{
            //修改
            updateDemoGen(state.formData).then(()=>{
              ElMessage.success('修改成功');
              closeDialog(); // 关闭弹窗
              emit('demoGenList')
            }).finally(()=>{
              state.loading = false;
            })
          }
        }
      });
    };
    const resetForm = ()=>{
      state.formData = {
        id: undefined,
        demoName: undefined,
        demoAge: undefined,
        classes: undefined,
        classesTwo: undefined,
        demoBorn: undefined,
        demoGender: false ,
        createdAt: undefined,
        updatedAt: undefined,
        deletedAt: undefined,
        createdBy: undefined,
        updatedBy: undefined,
        demoStatus: false ,
        demoCate: [] ,
        demoThumb: undefined,
        demoPhoto: [] ,
        demoInfo: undefined,
        demoFile: [] ,
        linkedDemoGenDemoGenClass: {
          id:undefined,    // 分类id
          className:undefined,    // 分类名
        },
      }
    };
    //关联demo_gen_class表选项
    const getDemoGenClassItemsClasses = () => {
      emit("getDemoGenClassItemsClasses")
    }
    //关联demo_gen_class表选项
    const getDemoGenClassItemsClassesTwo = () => {
      emit("getDemoGenClassItemsClassesTwo")
    }
    //单图上传头像
    const handleAvatarSuccessDemoThumb:UploadProps['onSuccess'] = (res, file) => {
      if (res.code === 0) {
        imageUrlDemoThumb.value = URL.createObjectURL(file.raw!)
        state.formData.demoThumb = res.data.path
      } else {
        ElMessage.error(res.msg)
      }
      upLoadingDemoThumb.value = false
    }
    const beforeAvatarUploadDemoThumb = () => {
      upLoadingDemoThumb.value = true
      return true
    }
    const setUpData = () => {
      return { token: getToken() }
    }
    const setUpImgListDemoPhoto = (data:any)=>{
      state.formData.demoPhoto = data
    }
    //富文本编辑器个人描述
    const setDemoInfoEditContent = (data:string) => {
      state.formData.demoInfo = data
    }
    const setUpFileListDemoFile = (data:any)=>{
      state.formData.demoFile = data
    }
    return {
      proxy,
      openDialog,
      closeDialog,
      onCancel,
      onSubmit,
      menuRef,
      formRef,
      getDemoGenClassItemsClasses,
      getDemoGenClassItemsClassesTwo,
      //图片上传地址
      imageUrlDemoThumb,
      //上传加载
      upLoadingDemoThumb,
      handleAvatarSuccessDemoThumb,
      beforeAvatarUploadDemoThumb,
      setUpData,
      setUpImgListDemoPhoto,
      //富文本编辑器个人描述
      setDemoInfoEditContent,
      setUpFileListDemoFile,
      baseURL,
      ...toRefs(state),
    };
  }
})
</script>
<style scoped>
.demo-demoGen-edit :deep(.avatar-uploader .avatar) {
  width: 178px;
  height: 178px;
  display: block;
}
.demo-demoGen-edit :deep(.avatar-uploader .el-upload) {
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}
.demo-demoGen-edit :deep(.avatar-uploader .el-upload:hover) {
  border-color: var(--el-color-primary);
}
.demo-demoGen-edit :deep(.el-icon.avatar-uploader-icon) {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}
</style>

src/views/demo/demoGen/component/detail.vue:

<template>
  <!-- 代码生成测试详情抽屉 -->
  <div class="demo-demoGen-detail">
    <el-drawer v-model="isShowDialog" size="80%" direction="ltr">
      <template #header>
        <h4>代码生成测试详情</h4>
      </template>
      <el-form ref="formRef" :model="formData" label-width="100px">
        <el-row>
          <el-col :span="12">
            <el-form-item label="ID">{{ formData.id }}</el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="姓名">{{ formData.demoName }}</el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="年龄">{{ formData.demoAge }}</el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="班级">{{ proxy.getOptionValue(formData.classes, getClassesOp) }}</el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="班级2">{{ proxy.getOptionValue(formData.classesTwo, getClassesTwoOp) }}</el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="出生年月">{{ proxy.parseTime(formData.demoBorn, '{y}-{m}-{d} {h}:{i}:{s}') }}</el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="性别">{{ proxy.getOptionValue(formData.demoGender, demoGenderOptions,'value','label') }}</el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="创建日期">{{ proxy.parseTime(formData.createdAt, '{y}-{m}-{d} {h}:{i}:{s}') }}</el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="创建人">{{ formData.createdBy }}</el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="修改人">{{ formData.updatedBy }}</el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="状态">{{ proxy.getOptionValue(formData.demoStatus, demoStatusOptions,'value','label') }}</el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="分类">
              <el-tag class="ml-2" type="success" v-for="(item,key) in formData.demoCate" :key="'demoCate-'+key">
                {{ proxy.getOptionValue(item, demoCateOptions,'value','label') }}
              </el-tag>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="头像">
              <el-image
                  style="width: 150px; height: 150px"
                  v-if="!proxy.isEmpty(formData.demoThumb)"
                  :src="proxy.getUpFileUrl(formData.demoThumb)"
                  fit="contain"></el-image>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="相册">
              <div class="pic-block" v-for="(img,key) in formData.demoPhoto" :key="'demoPhoto-'+key">
                <el-image
                    style="width: 150px; height: 150px"
                    v-if="!proxy.isEmpty(img.url)"
                    :src="proxy.getUpFileUrl(img.url)"
                    fit="contain"></el-image>
              </div>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="个人描述">
              <p v-html="formData.demoInfo"></p>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="相关附件">
              <div class="file-block" v-for="(item,key) in formData.demoFile" :key="'demoFile-'+key">
                <el-link type="primary" :underline="false"
                         :href="proxy.getUpFileUrl(item.url)" target="_blank">{{item.name}}</el-link>
              </div>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </el-drawer>
  </div>
</template>
<script lang="ts">
import { reactive, toRefs, defineComponent,ref,unref,getCurrentInstance,computed } from 'vue';
import {ElMessageBox, ElMessage, FormInstance,UploadProps} from 'element-plus';
import {
  listDemoGen,
  getDemoGen,
  delDemoGen,
  addDemoGen,
  updateDemoGen,
  listDemoGenClass,
  getUserList,
} from "/@/api/demo/demoGen";
import GfUeditor from "/@/components/ueditor/index.vue"
import {getToken} from "/@/utils/gfast"
import uploadImg from "/@/components/uploadImg/index.vue"
import uploadFile from "/@/components/uploadFile/index.vue"
import {
  DemoGenTableColumns,
  DemoGenInfoData,
  DemoGenTableDataState,
  DemoGenEditState,
  LinkedDemoGenDemoGenClass,
} from "/@/views/demo/demoGen/list/component/model"
export default defineComponent({
  name:"apiV1DemoDemoGenDetail",
  components:{
    GfUeditor,
    uploadImg,
    uploadFile,
  },
  props:{
    classesOptions:{
      type:Array,
      default:()=>[]
    },
    classesTwoOptions:{
      type:Array,
      default:()=>[]
    },
    demoGenderOptions:{
      type:Array,
      default:()=>[]
    },
    demoStatusOptions:{
      type:Array,
      default:()=>[]
    },
    demoCateOptions:{
      type:Array,
      default:()=>[]
    },
  },
  setup(props,{emit}) {
    const baseURL:string|undefined|boolean = import.meta.env.VITE_API_URL
    const {proxy} = <any>getCurrentInstance()
    const formRef = ref<HTMLElement | null>(null);
    const menuRef = ref();
    //图片上传地址
    const imageUrlDemoThumb = ref('')
    //上传加载
    const upLoadingDemoThumb = ref(false)
    const state = reactive<DemoGenEditState>({
      loading:false,
      isShowDialog: false,
      formData: {
        id: undefined,
        demoName: undefined,
        demoAge: undefined,
        classes: undefined,
        classesTwo: undefined,
        demoBorn: undefined,
        demoGender: false ,
        createdAt: undefined,
        updatedAt: undefined,
        deletedAt: undefined,
        createdBy: undefined,
        updatedBy: undefined,
        demoStatus: false ,
        demoCate: [] ,
        demoThumb: undefined,
        demoPhoto: [] ,
        demoInfo: undefined,
        demoFile: [] ,
        linkedDemoGenDemoGenClass: {
          id:undefined,    // 分类id
          className:undefined,    // 分类名
        },
      },
      // 表单校验
      rules: {
        id : [
          { required: true, message: "ID不能为空", trigger: "blur" }
        ],
        demoName : [
          { required: true, message: "姓名不能为空", trigger: "blur" }
        ],
        demoStatus : [
          { required: true, message: "状态不能为空", trigger: "blur" }
        ],
      }
    });
    // 打开弹窗
    const openDialog = (row?: DemoGenInfoData) => {
      resetForm();
      if(row) {
        getDemoGen(row.id!).then((res:any)=>{
          const data = res.data;
          data.demoCate = data.demoCate.split(",")
          //单图地址赋值
          imageUrlDemoThumb.value = data.demoThumb ? proxy.getUpFileUrl(data.demoThumb) : ''
          data.demoPhoto =data.demoPhoto?JSON.parse(data.demoPhoto) : []
          data.demoFile =data.demoFile?JSON.parse(data.demoFile) : []
          let listUid = [];
          listUid.push(data.createdBy,data.updatedBy)
          getUserList(listUid).then((response:any) =>{
            let users = response.data.list||[]
            users.forEach((user:any)=>{
              if(data.createdBy==user.id){
                data.createdBy = user.userNickname
              }
              if(data.updatedBy==user.id){
                data.updatedBy = user.userNickname
              }
            })
            state.formData = data;
          })
        })
      }
      state.isShowDialog = true;
    };
    // 关闭弹窗
    const closeDialog = () => {
      state.isShowDialog = false;
    };
    // 取消
    const onCancel = () => {
      closeDialog();
    };
    const resetForm = ()=>{
      state.formData = {
        id: undefined,
        demoName: undefined,
        demoAge: undefined,
        classes: undefined,
        classesTwo: undefined,
        demoBorn: undefined,
        demoGender: false ,
        createdAt: undefined,
        updatedAt: undefined,
        deletedAt: undefined,
        createdBy: undefined,
        updatedBy: undefined,
        demoStatus: false ,
        demoCate: [] ,
        demoThumb: undefined,
        demoPhoto: [] ,
        demoInfo: undefined,
        demoFile: [] ,
        linkedDemoGenDemoGenClass: {
          id:undefined,    // 分类id
          className:undefined,    // 分类名
        },
      }
    };
    //关联demo_gen_class表选项
    const getDemoGenClassItemsClasses = () => {
      emit("getDemoGenClassItemsClasses")
    }
    const getClassesOp = computed(()=>{
      getDemoGenClassItemsClasses()
      return props.classesOptions
    })
    //关联demo_gen_class表选项
    const getDemoGenClassItemsClassesTwo = () => {
      emit("getDemoGenClassItemsClassesTwo")
    }
    const getClassesTwoOp = computed(()=>{
      getDemoGenClassItemsClassesTwo()
      return props.classesTwoOptions
    })
    //单图上传头像
    const handleAvatarSuccessDemoThumb:UploadProps['onSuccess'] = (res, file) => {
      if (res.code === 0) {
        imageUrlDemoThumb.value = URL.createObjectURL(file.raw!)
        state.formData.demoThumb = res.data.path
      } else {
        ElMessage.error(res.msg)
      }
      upLoadingDemoThumb.value = false
    }
    const beforeAvatarUploadDemoThumb = () => {
      upLoadingDemoThumb.value = true
      return true
    }
    const setUpData = () => {
      return { token: getToken() }
    }
    const setUpImgListDemoPhoto = (data:any)=>{
      state.formData.demoPhoto = data
    }
    //富文本编辑器个人描述
    const setDemoInfoEditContent = (data:string) => {
      state.formData.demoInfo = data
    }
    const setUpFileListDemoFile = (data:any)=>{
      state.formData.demoFile = data
    }
    return {
      proxy,
      openDialog,
      closeDialog,
      onCancel,
      menuRef,
      formRef,
      getDemoGenClassItemsClasses,
      getClassesOp,
      getDemoGenClassItemsClassesTwo,
      getClassesTwoOp,
      //图片上传地址
      imageUrlDemoThumb,
      //上传加载
      upLoadingDemoThumb,
      handleAvatarSuccessDemoThumb,
      beforeAvatarUploadDemoThumb,
      setUpData,
      setUpImgListDemoPhoto,
      //富文本编辑器个人描述
      setDemoInfoEditContent,
      setUpFileListDemoFile,
      baseURL,
      ...toRefs(state),
    };
  }
})
</script>
<style scoped>
.demo-demoGen-detail :deep(.avatar-uploader .avatar) {
  width: 178px;
  height: 178px;
  display: block;
}
.demo-demoGen-detail :deep(.avatar-uploader .el-upload) {
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
}
.demo-demoGen-detail :deep(.avatar-uploader .el-upload:hover) {
  border-color: var(--el-color-primary);
}
.demo-demoGen-detail :deep(.el-icon.avatar-uploader-icon) {
  font-size: 28px;
  color: #8c939d;
  width: 178px;
  height: 178px;
  text-align: center;
}
.demo-demoGen-detail :deep(.el-form-item--large .el-form-item__label){
  font-weight: bolder;
}
.pic-block{
  margin-right: 8px;
}
.file-block{
  width: 100%;
  border: 1px solid var(--el-border-color);
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: var(--el-transition-duration-fast);
  margin-bottom: 5px;
  padding: 3px 6px;
}
.ml-2{margin-right: 5px;}
</style>
作者:管理员  创建时间:2023-01-06 15:44
最后编辑:管理员  更新时间:2024-12-03 15:05