wupengfei
2025-04-17 65c7175a1d7d448f91ee61a8a9aa935263939d37
feat: 接口对接
8个文件已添加
5个文件已修改
1243 ■■■■■ 已修改文件
src/constants/cPerson.ts 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/constants/enum.ts 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/constants/index.ts 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CPersonManage/CPersonManageList.vue 228 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/CPersonManage/components/CPersonDetailDialog.vue 197 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/EnterpriseManage/EnterpriseManageList.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/EnterpriseManage/components/AddOrEditEnterpriseView.vue 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/EnterpriseManage/components/ConfigureDialog.vue 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/OperationManage/OperationManageList.vue 209 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/OperationManage/components/AddOrEditAdvertisementDialog.vue 181 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/TaskManage/TaskManageDetail.vue 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/TaskManage/TaskManageList.vue 163 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/TaskManage/components/TaskDetailView.vue 75 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/constants/cPerson.ts
New file
@@ -0,0 +1,51 @@
export enum FlexWorkerEleSignEnum {
  /**
   * 未签约
   */
  WaitSign = 10,
  /**
   * 已签约
   */
  HasSign = 20,
  /**
   * 已解约
   */
  CancelSign = 30,
}
export const FlexWorkerEleSignEnumText = {
  [FlexWorkerEleSignEnum.WaitSign]: '未签约',
  [FlexWorkerEleSignEnum.HasSign]: '已签约',
  [FlexWorkerEleSignEnum.CancelSign]: '已解约',
};
export enum FlexTaskWorkerHireEnum {
  /**
   * 待签约
   */
  WaitForSign = 1,
  /**
   * 待处理
   */
  Wait = 10,
  /**
   * 已录用
   */
  Hired = 20,
  /**
   * 已谢绝
   */
  Refused = 30,
  /**
   * 已解约
   */
  CancelSign = 40,
}
export const FlexTaskWorkerHireEnumText = {
  [FlexTaskWorkerHireEnum.WaitForSign]: '待签约',
  [FlexTaskWorkerHireEnum.Wait]: '待处理',
  [FlexTaskWorkerHireEnum.Hired]: '已录用',
  [FlexTaskWorkerHireEnum.Refused]: '已谢绝',
  [FlexTaskWorkerHireEnum.CancelSign]: '已解约',
};
src/constants/enum.ts
@@ -43,3 +43,19 @@
  { label: '是', value: true },
  { label: '否', value: false },
];
export enum Gender {
  /**
   * 男
   */
  Male = 1,
  /**
   * 女
   */
  Female = 2,
}
export const GenderText = {
  [Gender.Male]: '男',
  [Gender.Female]: '女',
};
src/constants/index.ts
@@ -11,3 +11,4 @@
export * from './app';
export * from './dic';
export * from './enterprise';
export * from './cPerson';
src/views/CPersonManage/CPersonManageList.vue
New file
@@ -0,0 +1,228 @@
<template>
  <LoadingLayout :loading="state.loading">
    <AppContainer>
      <ProTableQueryFilterBar @on-reset="reset">
        <template #query>
          <QueryFilterItem tip-content="实名状态">
            <FieldRadio
              v-model="extraParamState.realVerifyStatus"
              :value-enum="[
                {
                  value: false,
                  label: '未实名',
                },
                {
                  value: true,
                  label: '已实名',
                },
              ]"
              buttonStyle
              showAllBtn
              @change="getList()"
            />
          </QueryFilterItem>
          <QueryFilterItem tip-content="最近录用时间">
            <FieldDatePicker
              v-model="extraParamState.nearlyHireDateTime"
              type="daterange"
              range-separator="~"
              start-placeholder="开始时间"
              end-placeholder="结束时间"
              clearable
              @change="getList()"
            ></FieldDatePicker>
          </QueryFilterItem>
          <QueryFilterItem tip-content="最近签约时间">
            <FieldDatePicker
              v-model="extraParamState.nearlySignDateTime"
              type="daterange"
              range-separator="~"
              start-placeholder="开始时间"
              end-placeholder="结束时间"
              clearable
              @change="getList()"
            ></FieldDatePicker>
          </QueryFilterItem>
          <QueryFilterItem>
            <SearchInput
              v-model="extraParamState.searchKeys"
              style="width: 300px"
              placeholder="姓名/手机/身份证号/客户"
              @on-click-search="getList"
              @keyup.enter="getList()"
            >
            </SearchInput>
          </QueryFilterItem>
        </template>
      </ProTableQueryFilterBar>
      <ProTableV2 v-bind="proTableProps" :columns="column" :operationBtns="operationBtns">
      </ProTableV2>
    </AppContainer>
    <CPersonDetailDialog v-bind="dialogProps"></CPersonDetailDialog>
  </LoadingLayout>
</template>
<script setup lang="ts">
import {
  ProTableQueryFilterBar,
  OperationBtnType,
  ProTableV2,
  SearchInput,
  LoadingLayout,
  AppContainer,
  QueryFilterItem,
  useTable,
  useFormDialog,
  FieldRadio,
  FieldDatePicker,
  UploadUserFile,
} from '@bole-core/components';
import { useAccess, useGlobalEventContext } from '@/hooks';
import * as flexEnterpriseWokerServices from '@/services/api/FlexEnterpriseWoker';
import { Gender } from '@/constants';
import CPersonDetailDialog from './components/CPersonDetailDialog.vue';
import { OrderInputType } from '@bole-core/core';
import { convertApi2FormUrlOnlyOne, format } from '@/utils';
import { ModelValueType } from 'element-plus';
defineOptions({
  name: 'CPersonManageList',
});
const operationBtnMap: Record<string, OperationBtnType> = {
  detailBtn: { emits: { onClick: (role) => openDialog(role) } },
};
const { checkSubModuleItemShow, column, operationBtns } = useAccess({
  operationBtnMap,
});
const eventContext = useGlobalEventContext();
eventContext.addEvent('enterprise:add', () => {
  getList();
});
eventContext.addEvent('enterprise:edit', () => {
  getList(paginationState.pageIndex);
});
const router = useRouter();
const BaseState = {
  loading: true,
};
const state = reactive({ ...BaseState });
onMounted(async () => {
  await getList();
  state.loading = false;
});
const {
  getDataSource: getList,
  proTableProps,
  paginationState,
  extraParamState,
  reset,
} = useTable(
  async ({ pageIndex, pageSize }, extraParamState) => {
    try {
      let params: API.GetUserClientForBackInput = {
        pageModel: {
          rows: pageSize,
          page: pageIndex,
          orderInput: extraParamState.orderInput,
        },
        searchKeys: extraParamState.searchKeys,
        nearlyHireDateTimeBegin: format(
          extraParamState.nearlyHireDateTime?.[0] ?? '',
          'YYYY-MM-DD 00:00:00'
        ),
        nearlyHireDateTimeEnd: format(
          extraParamState.nearlyHireDateTime?.[1] ?? '',
          'YYYY-MM-DD 23:59:59'
        ),
        nearlySignDateTimeBegin: format(
          extraParamState.nearlySignDateTime?.[0] ?? '',
          'YYYY-MM-DD 00:00:00'
        ),
        nearlySignDateTimeEnd: format(
          extraParamState.nearlySignDateTime?.[1] ?? '',
          'YYYY-MM-DD 23:59:59'
        ),
        realVerifyStatus: extraParamState.realVerifyStatus,
      };
      let res = await flexEnterpriseWokerServices.getUserClientList(params, {
        showLoading: !state.loading,
      });
      return res;
    } catch (error) {
      console.log('error: ', error);
    }
  },
  {
    defaultExtraParams: {
      searchKeys: '',
      realVerifyStatus: '' as any as boolean,
      nearlyHireDateTime: [] as unknown as ModelValueType,
      nearlySignDateTime: [] as unknown as ModelValueType,
      orderInput: [{ property: 'userId', order: OrderInputType.Desc }],
    },
    queryKey: ['flexEnterpriseWokerServices/getUserClientList'],
    columnsRenderProps: {
      realVerifyStatus: {
        type: 'enum',
        valueEnum: [
          { label: '已实名', value: true },
          { label: '未实名', value: false },
        ],
      },
      realVerifyTime: { type: 'date' },
    },
  }
);
async function openDialog(row?: API.GetUserClientForBackOutput) {
  const res = await getUserDetailForBack('98ac4c01-3598-ebf3-fa7d-3a189bb6b587');
  handleEdit({
    userId: row.userId ?? '98ac4c01-3598-ebf3-fa7d-3a189bb6b587',
    name: res.name,
    idNumber: res.idNumber,
    contactPhone: res.contactPhone,
    age: res.age,
    certificateFrontImgUrl: res.certificateFrontImgUrl
      ? convertApi2FormUrlOnlyOne(res.certificateFrontImgUrl)
      : [],
    certificateBackImgUrl: res.certificateBackImgUrl
      ? convertApi2FormUrlOnlyOne(res.certificateBackImgUrl)
      : [],
    genderType: Gender.Female,
    tabType: 'user',
  });
}
const { dialogProps, handleEdit } = useFormDialog({
  defaultFormParams: {
    userId: '',
    name: '',
    idNumber: '',
    contactPhone: '',
    age: 0,
    genderType: '' as any as Gender,
    certificateFrontImgUrl: [] as UploadUserFile[],
    certificateBackImgUrl: [] as UploadUserFile[],
    tabType: '',
  },
});
async function getUserDetailForBack(userId: string) {
  try {
    return await flexEnterpriseWokerServices.getUserDetailForBack({ userId: userId });
  } catch (error) {}
}
</script>
src/views/CPersonManage/components/CPersonDetailDialog.vue
New file
@@ -0,0 +1,197 @@
<template>
  <ProDialog title="申请详情" v-model="innerVisible" width="1200px" destroy-on-close>
    <ProTabs v-model="innerForm.tabType" hasBorder>
      <ProTabPane lazy label="人员详情" name="user">
        <ProForm :model="form" ref="dialogForm" label-width="120px" is-read>
          <ProFormItemV2 label="姓名:" prop="name">
            <ProFormText v-model.trim="innerForm.name" />
          </ProFormItemV2>
          <ProFormItemV2 label="身份证号:" prop="idNumber">
            <ProFormText v-model.trim="innerForm.idNumber" />
          </ProFormItemV2>
          <ProFormItemV2 label="手机号:" prop="contactPhone">
            <ProFormText v-model.trim="innerForm.contactPhone" />
          </ProFormItemV2>
          <ProFormItemV2 label="性别:" prop="age">
            <ProFormRadio v-model="innerForm.genderType" :value-enum="GenderText"></ProFormRadio>
          </ProFormItemV2>
          <ProFormItemV2 label="年龄:" prop="age">
            <ProFormInputNumber v-model="innerForm.age" unit="岁"></ProFormInputNumber>
          </ProFormItemV2>
          <ProFormItemV2 label="身份证正面:" prop="certificateFrontImgUrl">
            <ProFormImageUpload v-model:file-url="innerForm.certificateFrontImgUrl" />
          </ProFormItemV2>
          <ProFormItemV2 label="身份证反面:" prop="certificateBackImgUrl">
            <ProFormImageUpload v-model:file-url="innerForm.certificateBackImgUrl" />
          </ProFormItemV2>
        </ProForm>
      </ProTabPane>
      <ProTabPane lazy label="签约详情" name="sign">
        <ProDialogTableWrapper :height="400">
          <ProTableV2 v-bind="proTableProps" :columns="column" :show-operation-column="false">
          </ProTableV2>
        </ProDialogTableWrapper>
      </ProTabPane>
    </ProTabs>
  </ProDialog>
</template>
<script setup lang="ts">
import {
  ProDialog,
  ProTableV2,
  ProDialogTableWrapper,
  ProTabs,
  ProTabPane,
  useTable,
  ProForm,
  ProFormItemV2,
  ProFormText,
  UploadUserFile,
  ProFormImageUpload,
  ProFormRadio,
  ProFormInputNumber,
} from '@bole-core/components';
import { OrderInputType } from '@bole-core/core';
import _ from 'lodash';
import * as flexEnterpriseWokerServices from '@/services/api/FlexEnterpriseWoker';
import { setOSSLink } from '@/utils';
import { FlexTaskWorkerHireEnumText, FlexWorkerEleSignEnumText, Gender, GenderText } from '@/constants';
defineOptions({
  name: 'CPersonDetailDialog',
});
type Props = {
  modelValue: boolean;
  form: {
    tabType: string;
    userId: string;
    name: string;
    idNumber: string;
    contactPhone: string;
    age: number;
    genderType:Gender;
    certificateFrontImgUrl: UploadUserFile[];
    certificateBackImgUrl: UploadUserFile[];
  };
};
const props = withDefaults(defineProps<Props>(), {
  modelValue: false,
});
const emit = defineEmits<{
  (e: 'update:modelValue', value: boolean): void;
  (e: 'update:form', value: Props['form']): void;
  (e: 'onCancel'): void;
}>();
const column: API.CustomModuleColumnDto[] = [
  {
    id: '1',
    enCode: 'enterpirseName',
    name: '所属客户',
  },
  {
    id: '2',
    enCode: 'applyTime',
    name: '报名时间',
  },
  {
    id: '3',
    enCode: 'hireStatus',
    name: '录用状态',
  },
  {
    id: '4',
    enCode: 'hireDateTime',
    name: '录用时间',
  },
  {
    id: '5',
    enCode: 'userSignStatus',
    name: '签约状态',
  },
  {
    id: '6',
    enCode: 'enterSignStatus',
    name: '企业签约状态',
  },
  {
    id: '7',
    enCode: 'enterSignTime',
    name: '企业签约时间',
  },
  {
    id: '8',
    enCode: 'contractUrl',
    name: '电子合同',
  },
];
const innerVisible = computed({
  get() {
    return props.modelValue;
  },
  set(val) {
    emit('update:modelValue', val);
  },
});
const innerForm = computed({
  get() {
    return props.form;
  },
  set(val) {
    emit('update:form', val);
  },
});
watch(
  () => innerVisible.value,
  (val) => {
    if (val) {
      getList();
    }
  }
);
const {
  getDataSource: getList,
  proTableProps,
  paginationState,
  extraParamState,
} = useTable(
  async ({ pageIndex, pageSize }, extraParamState) => {
    try {
      let params: API.GetUserClientSignListInput = {
        pageModel: {
          rows: pageSize,
          page: pageIndex,
          orderInput: extraParamState.orderInput,
        },
        userId: props.form.userId,
      };
      let res = await flexEnterpriseWokerServices.getUserClientSignList(params);
      return res;
    } catch (error) {}
  },
  {
    defaultExtraParams: {
      orderInput: [{ property: 'applyTime', order: OrderInputType.Desc }],
    },
    columnsRenderProps: {
      applyTime: { type: 'date' },
      hireDateTime: { type: 'date' },
      userSignTime: { type: 'date' },
      hireStatus: { type: 'enum', valueEnum: FlexTaskWorkerHireEnumText },
      userSignStatus: { type: 'enum', valueEnum: FlexWorkerEleSignEnumText },
      enterSignStatus: { type: 'enum', valueEnum: FlexWorkerEleSignEnumText },
    },
  }
);
</script>
<style lang="scss" scoped>
@use '@/style/common.scss' as *;
</style>
src/views/EnterpriseManage/EnterpriseManageList.vue
@@ -144,7 +144,7 @@
  {
    defaultExtraParams: {
      searchWord: '',
      orderInput: [{ property: 'id', order: OrderInputType.Asc }],
      orderInput: [{ property: 'id', order: OrderInputType.Desc }],
      flexEnterpriseSettingStatus: '' as any as FlexEnterpriseSettingStatus,
    },
    queryKey: ['flexEnterpriseServices/getFlexEnterpriseList'],
@@ -159,21 +159,24 @@
  if (row) {
    handleEdit({
      id: row.id,
      enterpriseConfigureType: EnterpriseConfigureType.Bank,
      flexEnterpirseId: row.id,
      openBank: row.cityName,
      openBranchBank: row.cityName,
      bankAccount: row.cityName,
      verifyStatus: VerifyStatus.NotVerify,
      signChannel: SignChannelEnum.Alipay,
      chargeType: ChargeTypeEnum.Group,
      realVerifyCost: 0,
      signCost: 0,
      mergeSignCost: 0,
      messageCost: 0,
      messageChannel: MessageChannelEnum.Alipay,
      openBank: row.flexEnterpriseBankDto?.openBank,
      openBranchBank: row.flexEnterpriseBankDto?.openBranchBank,
      bankAccount: row.flexEnterpriseBankDto?.bankAccount,
      verifyStatus: row.flexEnterpriseBankDto?.verifyStatus,
      signChannel: row.enterpriseSignSettingDto?.signChannel,
      chargeType: row.enterpriseSignSettingDto?.chargeType,
      realVerifyCost: row.enterpriseSignSettingDto?.realVerifyCost ?? 0,
      signCost: row.enterpriseSignSettingDto?.signCost ?? 0,
      mergeSignCost: row.enterpriseSignSettingDto?.mergeSignCost ?? 0,
      messageCost: row.flexEnterpriseMessageSettingDto?.messageCost ?? 0,
      messageChannel: row.flexEnterpriseMessageSettingDto?.messageChannel,
    });
  } else {
    handleAdd({});
    handleAdd({
      enterpriseConfigureType: EnterpriseConfigureType.Bank,
    });
  }
}
@@ -182,6 +185,7 @@
  defaultFormParams: {
    id: '',
    flexEnterpirseId: '',
    enterpriseConfigureType: '' as any as EnterpriseConfigureType,
    openBank: '',
    openBranchBank: '',
    bankAccount: '',
src/views/EnterpriseManage/components/AddOrEditEnterpriseView.vue
@@ -2,14 +2,18 @@
  <LoadingLayout :loading="isEdit && isLoading">
    <AppScrollContainer>
      <ChunkCell title="企业基本信息">
        <ProForm :model="form" :rules="rules" ref="formRef" label-width="120px" :is-read="isDetail">
        <ProForm :model="form" ref="formRef" label-width="140px" :is-read="isDetail">
          <ProFormCol>
            <ProFormColItem :span="12">
              <ProFormItemV2 label="企业名称:" prop="enterpriseName">
              <ProFormItemV2
                label="企业名称:"
                prop="enterpriseName"
                :check-rules="[{ message: '请输入企业名称' }]"
              >
                <ProFormText
                  v-model.trim="form.enterpriseName"
                  :maxlength="30"
                  placeholder="请输入供应商名称"
                  placeholder="请输入企业名称"
                />
              </ProFormItemV2>
            </ProFormColItem>
@@ -38,7 +42,11 @@
          </ProFormCol>
          <ProFormCol>
            <ProFormColItem :span="12">
              <ProFormItemV2 label="统一社会信用代码:" prop="societyCreditCode">
              <ProFormItemV2
                label="统一社会信用代码:"
                prop="societyCreditCode"
                :check-rules="[{ message: '请输入统一社会信用代码', type: 'societyCreditCode' }]"
              >
                <ProFormText
                  v-model.trim="form.societyCreditCode"
                  placeholder="请输入统一社会信用代码"
@@ -100,7 +108,6 @@
      <ChunkCell title="联系信息">
        <ProForm
          :model="form"
          :rules="rules"
          ref="settingFormRef"
          label-width="140px"
          :scroll-to-error="false"
@@ -108,7 +115,11 @@
        >
          <ProFormCol>
            <ProFormColItem :span="12">
              <ProFormItemV2 label="联系人:" prop="contact">
              <ProFormItemV2
                label="联系人:"
                prop="contact"
                :check-rules="[{ message: '请输入联系人' }]"
              >
                <ProFormText
                  v-model.trim="form.contact"
                  :maxlength="30"
@@ -119,7 +130,11 @@
          </ProFormCol>
          <ProFormCol>
            <ProFormColItem :span="12">
              <ProFormItemV2 label="联系电话:" prop="contactPhone">
              <ProFormItemV2
                label="联系电话:"
                prop="contactPhone"
                :check-rules="[{ message: '请输入联系电话', type: 'phone' }]"
              >
                <ProFormText v-model.trim="form.contactPhone" placeholder="请输入联系电话" />
              </ProFormItemV2>
            </ProFormColItem>
@@ -141,7 +156,6 @@
      <ChunkCell title="账号信息">
        <ProForm
          :model="form"
          :rules="rules"
          ref="accountFormRef"
          label-width="140px"
          :scroll-to-error="false"
@@ -149,7 +163,11 @@
        >
          <ProFormCol>
            <ProFormColItem :span="12">
              <ProFormItemV2 label="账号:" prop="contact">
              <ProFormItemV2
                label="账号:"
                prop="contact"
                :check-rules="[{ message: '请输入账号' }]"
              >
                <ProFormText v-model.trim="form.contact" :maxlength="30" placeholder="请输入账号" />
              </ProFormItemV2>
            </ProFormColItem>
@@ -244,15 +262,6 @@
const formRef = ref<FormInstance>();
const settingFormRef = ref<FormInstance>();
const accountFormRef = ref<FormInstance>();
const rules = reactive<FormRules>({
  enterpriseName: [{ required: true, message: '请输入企业名称', trigger: 'blur' }],
  contact: [{ required: true, message: '请输入联系人', trigger: 'blur' }],
  contactPhone: [
    { required: true, message: '请输入联系电话', trigger: 'blur' },
    { message: '请输入正确的联系电话', trigger: 'blur', pattern: BoleRegExp.RegPhoneNumber },
  ],
});
async function handleSubmit() {
  try {
src/views/EnterpriseManage/components/ConfigureDialog.vue
@@ -3,12 +3,12 @@
    <ProForm :model="innerForm" ref="dialogForm" label-width="100px">
      <ProFormItemV2 label="" prop="enterpriseConfigureType" label-width="0">
        <ProFormRadio
          v-model="enterpriseConfigureType"
          v-model="innerForm.enterpriseConfigureType"
          :value-enum="EnterpriseConfigureTypeText"
          buttonStyle
        />
      </ProFormItemV2>
      <template v-if="enterpriseConfigureType === EnterpriseConfigureType.Bank">
      <template v-if="innerForm.enterpriseConfigureType === EnterpriseConfigureType.Bank">
        <ProFormItemV2 label="开户总行:" prop="openBank">
          <ProFormText
            v-model.trim="innerForm.openBank"
@@ -40,7 +40,7 @@
          >
        </ProFormItemV2>
      </template>
      <template v-if="enterpriseConfigureType === EnterpriseConfigureType.Electronic">
      <template v-if="innerForm.enterpriseConfigureType === EnterpriseConfigureType.Electronic">
        <div class="configure-dialog-form-title">通道配置</div>
        <ProFormItemV2
          label="名称:"
@@ -95,7 +95,7 @@
          </ProFormItemV2>
        </template>
      </template>
      <template v-if="enterpriseConfigureType === EnterpriseConfigureType.ShortMessage">
      <template v-if="innerForm.enterpriseConfigureType === EnterpriseConfigureType.ShortMessage">
        <div class="configure-dialog-form-title">通道配置</div>
        <ProFormItemV2
          label="名称:"
@@ -162,6 +162,7 @@
type Props = {
  modelValue: boolean;
  form?: {
    enterpriseConfigureType: EnterpriseConfigureType;
    openBank: string;
    openBranchBank: string;
    bankAccount: string;
@@ -180,12 +181,10 @@
  modelValue: false,
});
const enterpriseConfigureType = ref<EnterpriseConfigureType>(EnterpriseConfigureType.Bank);
const emit = defineEmits<{
  (e: 'update:modelValue', value: boolean): void;
  (e: 'update:form', value: Props['form']): void;
  (e: 'onConfirm', value: EnterpriseConfigureType): void;
  (e: 'onConfirm'): void;
  (e: 'onCancel'): void;
}>();
@@ -220,7 +219,7 @@
  if (!dialogForm.value) return;
  dialogForm.value.validate((valid) => {
    if (valid) {
      emit('onConfirm', enterpriseConfigureType.value);
      emit('onConfirm');
    } else {
      return;
    }
src/views/OperationManage/OperationManageList.vue
New file
@@ -0,0 +1,209 @@
<template>
  <LoadingLayout :loading="state.loading">
    <AppContainer>
      <ProTableQueryFilterBar @on-reset="reset">
        <template #query>
          <QueryFilterItem>
            <FieldSelect
              v-model="extraParamState.pageType"
              placeholder="广告页面"
              :value-enum="FlexWorkerEleSignEnumText"
              clearable
              @change="getAdvertiseOnShowList()"
            />
          </QueryFilterItem>
          <QueryFilterItem tip-content="状态">
            <FieldRadio
              v-model="extraParamState.status"
              :value-enum="FlexWorkerEleSignEnumText"
              buttonStyle
              showAllBtn
              @change="getAdvertiseOnShowList()"
            />
          </QueryFilterItem>
          <QueryFilterItem tip-content="广告开始时间">
            <FieldDatePicker
              v-model="extraParamState.beginDate"
              type="daterange"
              range-separator="~"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              clearable
              @change="getAdvertiseOnShowList()"
            ></FieldDatePicker>
          </QueryFilterItem>
          <QueryFilterItem tip-content="广告结束时间">
            <FieldDatePicker
              v-model="extraParamState.endDate"
              type="daterange"
              range-separator="~"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              clearable
              @change="getAdvertiseOnShowList()"
            ></FieldDatePicker>
          </QueryFilterItem>
          <QueryFilterItem>
            <SearchInput
              v-model="extraParamState.keyword"
              style="width: 260px"
              placeholder="广告名称"
              @on-click-search="getAdvertiseOnShowList"
            >
            </SearchInput>
          </QueryFilterItem>
        </template>
        <template #btn>
          <el-button
            v-if="checkSubModuleItemShow('pageButton', 'addBtn')"
            @click="openDialog()"
            icon="Plus"
            type="primary"
            >新增</el-button
          >
        </template>
      </ProTableQueryFilterBar>
      <ProTableV2 v-bind="proTableProps" :columns="column" :operationBtns="operationBtns">
      </ProTableV2>
    </AppContainer>
  </LoadingLayout>
</template>
<script setup lang="ts">
import {
  ProTableQueryFilterBar,
  OperationBtnType,
  ProTableV2,
  SearchInput,
  LoadingLayout,
  AppContainer,
  QueryFilterItem,
  useTable,
  useFormDialog,
  FieldDatePicker,
  FieldSelect,
  FieldRadio,
  UploadUserFile,
} from '@bole-core/components';
import { useAccess } from '@/hooks';
import { FlexWorkerEleSignEnumText } from '@/constants';
import { ModelValueType } from 'element-plus';
import * as flexEnterpriseWokerServices from '@/services/api/FlexEnterpriseWoker';
import { format, setOSSLink, convertApi2FormUrl, convertFormUrl2Api } from '@/utils';
import { OrderInputType, Message } from '@bole-core/core';
defineOptions({
  name: 'OperationManageList',
});
const operationBtnMap: Record<string, OperationBtnType> = {
  editBtn: { emits: { onClick: (role) => openDialog(role) } },
  takeOnBtn: {
    emits: { onClick: (role) => setAdvertiseOnShowStatus(role) },
    extraProps: {
      hide: (row) => row.status,
    },
  },
  takeDownBtn: {
    emits: { onClick: (role) => setAdvertiseOnShowStatus(role) },
    props: { type: 'danger' },
    extraProps: {
      hide: (row) => !row.status,
    },
  },
  logBtn: { emits: { onClick: (role) => openDialog(role) } },
};
const { checkSubModuleItemShow, column, operationBtns } = useAccess({
  operationBtnMap,
});
const BaseState = {
  loading: true,
};
const state = reactive({ ...BaseState });
onMounted(async () => {
  await getAdvertiseOnShowList();
  state.loading = false;
});
const {
  getDataSource: getAdvertiseOnShowList,
  proTableProps,
  paginationState,
  extraParamState,
  reset,
} = useTable(
  async ({ pageIndex, pageSize }, extraParamState) => {
    try {
      let params: API.GetUserClientForBackInput = {
        pageModel: {
          rows: pageSize,
          page: pageIndex,
          orderInput: extraParamState.orderInput,
        },
        searchKeys: extraParamState.keyword,
      };
      let res = await flexEnterpriseWokerServices.getUserClientList(params, {
        showLoading: !state.loading,
      });
      return res;
    } catch (error) {}
  },
  {
    defaultExtraParams: {
      keyword: '',
      pageType: '' as any as number,
      status: '' as any as boolean,
      beginDate: [] as unknown as ModelValueType,
      endDate: [] as unknown as ModelValueType,
      orderInput: [{ property: 'sort', order: OrderInputType.Asc }],
    },
    columnsRenderProps: {},
    columnPropsMap: ['advertiseBeginDate', 'advertiseEndDate'],
  }
);
function openDialog(row?) {
  if (row) {
    handleEdit({
      id: row.id,
      pageType: row.pageType,
      advertiseName: row.advertiseName,
      advertiseLink: row.advertiseLink,
      imgInfo: row.imgInfo.map((x) => convertApi2FormUrl(x.imgUrl)),
      date: [format(row.advertiseBeginDate), format(row.advertiseEndDate)],
      sort: row.sort,
    });
  } else {
    handleAdd();
  }
}
const { dialogProps, handleAdd, handleEdit, editForm, dialogState } = useFormDialog({
  onConfirm: handleAddOrEdit,
  defaultFormParams: {
    title: '新增广告',
    id: '',
    pageType: '' as any as number,
    advertiseName: '',
    advertiseLink: '',
    imgInfo: [] as UploadUserFile[],
    date: [] as unknown as ModelValueType,
    sort: 0,
  },
  editTitle: '编辑广告',
});
async function handleAddOrEdit() {
  try {
  } catch (error) {}
}
async function setAdvertiseOnShowStatus(row) {
  try {
  } catch (error) {}
}
</script>
src/views/OperationManage/components/AddOrEditAdvertisementDialog.vue
New file
@@ -0,0 +1,181 @@
<template>
  <ProDialog
    :title="innerForm.title"
    v-model="innerVisible"
    @close="onDialogClose"
    destroy-on-close
  >
    <ProForm :rules="rules" :model="innerForm" ref="dialogForm" label-width="120px">
      <ProFormItemV2
        label="广告页面:"
        prop="pageType"
        :check-rules="[{ message: '请选择广告页面' }]"
      >
        <ProFormSelect
          placeholder="请选择广告页面"
          :value-enum="FlexWorkerEleSignEnumText"
          clearable
          v-model="innerForm.pageType"
        ></ProFormSelect>
      </ProFormItemV2>
      <ProFormItemV2
        label="广告名称:"
        prop="advertiseName"
        :check-rules="[{ message: '请输入广告名称' }, { max: 20, message: '不能超过20个字符' }]"
      >
        <ProFormText
          placeholder="请输入广告名称"
          v-model.trim="innerForm.advertiseName"
          :maxlength="20"
        ></ProFormText>
      </ProFormItemV2>
      <ProFormItemV2
        label="广告产品链接:"
        prop="advertiseLink"
        :check-rules="[
          { type: 'urlWithParams', message: '请输入广告产品链接' },
          { message: '请输入正确的广告产品链接' },
        ]"
      >
        <ProFormText
          placeholder="请输入广告产品链接"
          v-model.trim="innerForm.advertiseLink"
          :maxlength="150"
        ></ProFormText>
      </ProFormItemV2>
      <ProFormItemV2
        label="广告图片:"
        prop="imgInfo"
        :check-rules="[{ type: 'array', message: '请选择广告图片' }]"
      >
        <ProFormImageUpload
          :fileDirectory="OssAdvertise"
          v-model:file-url="innerForm.imgInfo"
          :limitFileCount="1"
        ></ProFormImageUpload>
      </ProFormItemV2>
      <ProFormItemV2
        label="广告日期:"
        prop="date"
        :check-rules="[{ type: 'array', message: '请选择广告日期' }]"
      >
        <ProFormDatePicker
          v-model="innerForm.date"
          type="daterange"
          range-separator="~"
          start-placeholder="广告起始日期"
          end-placeholder="广告到期日期"
          clearable
        ></ProFormDatePicker>
      </ProFormItemV2>
      <ProFormItemV2
        label="广告位排序:"
        prop="sort"
        required
        :check-rules="[{ message: '请输入排序' }]"
      >
        <ProFormInputNumber
          v-model="innerForm.sort"
          :controls="false"
          :min="0"
          :max="99"
        ></ProFormInputNumber>
      </ProFormItemV2>
    </ProForm>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="emit('onCancel')">取 消</el-button>
        <el-button type="primary" @click="handleConfirm">确 定</el-button>
      </span>
    </template>
  </ProDialog>
</template>
<script setup lang="ts">
import { FormRules, FormInstance } from 'element-plus';
import {
  ProDialog,
  ProForm,
  ProFormItemV2,
  UploadUserFile,
  ProFormText,
  ProFormDatePicker,
  ProFormInputNumber,
  ProFormSelect,
  ProFormImageUpload,
} from '@bole-core/components';
import { ModelValueType } from 'element-plus';
import { OssAdvertise, FlexWorkerEleSignEnumText } from '@/constants';
import { BoleRegExp } from '@bole-core/core';
defineOptions({
  name: 'AddOrEditAdvertisementDialog',
});
type Props = {
  modelValue: boolean;
  form?: {
    title?: string;
    id: string;
    pageType: number;
    advertiseName: string;
    advertiseLink: string;
    imgInfo: UploadUserFile[];
    date: ModelValueType;
    sort: number;
  };
};
const props = withDefaults(defineProps<Props>(), {
  modelValue: false,
});
const emit = defineEmits<{
  (e: 'update:modelValue', value: boolean): void;
  (e: 'update:form', value: Props['form']): void;
  (e: 'onConfirm'): void;
  (e: 'onCancel'): void;
}>();
const dialogForm = ref<FormInstance>();
const innerVisible = computed({
  get() {
    return props.modelValue;
  },
  set(val) {
    emit('update:modelValue', val);
  },
});
const innerForm = computed({
  get() {
    return props.form;
  },
  set(val) {
    emit('update:form', val);
  },
});
const rules = reactive<FormRules>({
  contacterPhone: [
    { message: '请输入正确的联系电话', trigger: 'blur', pattern: BoleRegExp.RegTelNumber },
  ],
});
function onDialogClose() {
  if (!dialogForm.value) return;
  dialogForm.value.resetFields();
}
function handleConfirm() {
  if (!dialogForm.value) return;
  dialogForm.value.validate((valid) => {
    if (valid) {
      emit('onConfirm');
    } else {
      return;
    }
  });
}
</script>
src/views/TaskManage/TaskManageDetail.vue
New file
@@ -0,0 +1,32 @@
<template>
  <LoadingLayout>
    <AppContainer>
      <ProTabs v-model="state.tabType" hasBorder>
        <ProTabPane lazy label="任务详情" name="task">
          <TaskDetailView></TaskDetailView>
        </ProTabPane>
        <ProTabPane lazy label="报名详情" name="sign">
          <SignDetailView></SignDetailView>
        </ProTabPane>
      </ProTabs>
    </AppContainer>
  </LoadingLayout>
</template>
<script setup lang="ts">
import { AppContainer, ProTabs, ProTabPane } from '@bole-core/components';
import TaskDetailView from './components/TaskDetailView.vue';
import SignDetailView from './components/SignDetailView.vue';
defineOptions({
  name: 'TaskManageDetail',
});
const state = reactive({
  tabType: 'task',
});
</script>
<style lang="scss" scoped>
@use '@/style/common.scss' as *;
</style>
src/views/TaskManage/TaskManageList.vue
New file
@@ -0,0 +1,163 @@
<template>
  <LoadingLayout :loading="state.loading">
    <AppContainer>
      <ProTableQueryFilterBar @on-reset="reset">
        <template #query>
          <QueryFilterItem>
            <FieldSelect
              v-model="extraParamState.pageType"
              placeholder="广告页面"
              :value-enum="FlexWorkerEleSignEnumText"
              clearable
              @change="getList()"
            />
          </QueryFilterItem>
          <QueryFilterItem tip-content="发布状态">
            <FieldRadio
              v-model="extraParamState.status"
              :value-enum="FlexWorkerEleSignEnumText"
              buttonStyle
              showAllBtn
              @change="getList()"
            />
          </QueryFilterItem>
          <QueryFilterItem tip-content="推荐状态">
            <FieldRadio
              v-model="extraParamState.status"
              :value-enum="FlexWorkerEleSignEnumText"
              buttonStyle
              showAllBtn
              @change="getList()"
            />
          </QueryFilterItem>
          <QueryFilterItem tip-content="发布时间">
            <FieldDatePicker
              v-model="extraParamState.beginDate"
              type="daterange"
              range-separator="~"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              clearable
              @change="getList()"
            ></FieldDatePicker>
          </QueryFilterItem>
          <QueryFilterItem>
            <SearchInput
              v-model="extraParamState.keyword"
              style="width: 260px"
              placeholder="任务名称"
              @on-click-search="getList"
            >
            </SearchInput>
          </QueryFilterItem>
        </template>
      </ProTableQueryFilterBar>
      <ProTableV2 v-bind="proTableProps" :columns="column" :operationBtns="operationBtns">
      </ProTableV2>
    </AppContainer>
  </LoadingLayout>
</template>
<script setup lang="ts">
import {
  ProTableQueryFilterBar,
  OperationBtnType,
  ProTableV2,
  SearchInput,
  LoadingLayout,
  AppContainer,
  QueryFilterItem,
  useTable,
  FieldDatePicker,
  FieldSelect,
  FieldRadio,
} from '@bole-core/components';
import { useAccess } from '@/hooks';
import { FlexWorkerEleSignEnumText } from '@/constants';
import { ModelValueType } from 'element-plus';
import * as flexEnterpriseWokerServices from '@/services/api/FlexEnterpriseWoker';
import { OrderInputType } from '@bole-core/core';
defineOptions({
  name: 'OperationManageList',
});
const operationBtnMap: Record<string, OperationBtnType> = {
  detailBtn: { emits: { onClick: (role) => goDetail(role) } },
  takeOnBtn: {
    emits: { onClick: (role) => setAdvertiseOnShowStatus(role) },
    extraProps: {
      hide: (row) => row.status,
    },
  },
  takeDownBtn: {
    emits: { onClick: (role) => setAdvertiseOnShowStatus(role) },
    props: { type: 'danger' },
    extraProps: {
      hide: (row) => !row.status,
    },
  },
};
const { checkSubModuleItemShow, column, operationBtns } = useAccess({
  operationBtnMap,
});
const router = useRouter();
const BaseState = {
  loading: true,
};
const state = reactive({ ...BaseState });
onMounted(async () => {
  await getList();
  state.loading = false;
});
const {
  getDataSource: getList,
  proTableProps,
  paginationState,
  extraParamState,
  reset,
} = useTable(
  async ({ pageIndex, pageSize }, extraParamState) => {
    try {
      let params: API.GetUserClientForBackInput = {
        pageModel: {
          rows: pageSize,
          page: pageIndex,
          orderInput: extraParamState.orderInput,
        },
        searchKeys: extraParamState.keyword,
      };
      let res = await flexEnterpriseWokerServices.getUserClientList(params, {
        showLoading: !state.loading,
      });
      return res;
    } catch (error) {}
  },
  {
    defaultExtraParams: {
      keyword: '',
      pageType: '' as any as number,
      status: '' as any as boolean,
      beginDate: [] as unknown as ModelValueType,
      endDate: [] as unknown as ModelValueType,
      orderInput: [{ property: 'sort', order: OrderInputType.Asc }],
    },
    columnsRenderProps: {},
    columnPropsMap: ['advertiseBeginDate', 'advertiseEndDate'],
  }
);
async function setAdvertiseOnShowStatus(row) {
  try {
  } catch (error) {}
}
function goDetail(row) {
  router.push({ name: 'TaskDetail', params: { id: row?.id ?? '' } });
}
</script>
src/views/TaskManage/components/TaskDetailView.vue
New file
@@ -0,0 +1,75 @@
<template>
  <LoadingLayout :loading="isLoading">
    <AppContainer>
      <PageFormLayout>
        <ProForm :model="detail" ref="formRef" label-width="140px" is-read>
          <ProFormCol>
            <ProFormColItem :span="12">
              <ProFormItemV2 label="任务名称:" prop="name">
                <ProFormText v-model.trim="detail.name" />
              </ProFormItemV2>
            </ProFormColItem>
          </ProFormCol>
          <ProFormCol>
            <ProFormColItem :span="12">
              <ProFormItemV2 label="任务名称:" prop="name">
                <RadioWithExtra
                  v-model="detail"
                  :value-enum="TrainSalaryTypeTextList"
                  enumLabelKey="text"
                  enum-value-key="value"
                  :showExtra="state.consultForm.salaryType === ConsultSalaryType.Input"
                >
                  <template #extra>
                    <ProFormInputNumber
                      :controls="false"
                      :min="0"
                      :max="999"
                      v-model="state.consultForm.startMonthlySalary"
                      placeholder="请输入"
                    ></ProFormInputNumber>
                  </template>
                </RadioWithExtra>
              </ProFormItemV2>
            </ProFormColItem>
          </ProFormCol>
        </ProForm>
      </PageFormLayout>
    </AppContainer>
  </LoadingLayout>
</template>
<script setup lang="ts">
import {
  LoadingLayout,
  AppContainer,
  PageFormLayout,
  ProForm,
  ProFormCol,
  ProFormColItem,
  ProFormItemV2,
  ProFormText,
  ProFormInputNumber,
} from '@bole-core/components';
import { useQuery } from '@tanstack/vue-query';
defineOptions({
  name: 'TaskDetailView',
});
const route = useRoute();
const id = route.params?.id as string;
const { data: detail, isLoading } = useQuery({
  //   queryKey: ['customerServices/getParkCustomerManageBaseDetail', id],
  //   queryFn: async () => {
  //     return await customerServices.getParkCustomerManageBaseDetail({ id: id });
  //   },
  placeholderData: () => ({} as API.GetUserClientForBackOutput),
  //   enabled: !!id,
});
</script>
<style lang="scss" scoped>
@use '@/style/common.scss' as *;
</style>