| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578 |
- <!-- 模板区域 -->
- <template>
- <div class="body">
- <div class="card">
- <a-form ref="formRef" :model="distributionRecordForm" layout="vertical" labelAlign="right" :label-col="labelCol"
- :rules="distributionRecordFormRules">
- <div class="card-header dis a-c mb-2">
- <div class="link"></div>
- <span>基本信息</span>
- </div>
- <div class="horizontal-section">
- <a-row :gutter="30">
- <a-col :span="6">
- <a-form-item label="发放渠道" name="institutionId">
- <a-tree-select v-model:value="distributionRecordForm.institutionId" @change="institutionChange"
- show-search style="width: 100%" :dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
- placeholder="Please select" allow-clear tree-default-expand-all :tree-data="treeData" :field-names="{
- children: 'node',
- label: 'institutionName',
- value: 'id',
- }" tree-node-filter-prop="institutionName">
- </a-tree-select>
- </a-form-item>
- </a-col>
- <a-col :span="6">
- <a-form-item label="发放人" name="grantUserName">
- <a-input v-model:value="distributionRecordForm.grantUserName" showCount maxlength="20"
- placeholder="请输入发放人" />
- </a-form-item>
- </a-col>
- <a-col :span="6">
- <a-form-item label="发放人手机号" name="grantUserPhone">
- <a-input v-model:value="distributionRecordForm.grantUserPhone" showCount maxlength="11"
- placeholder="请输入发放人手机号" allowClear />
- </a-form-item>
- </a-col>
- <a-col :span="12">
- <a-form-item label="备注">
- <a-textarea v-model:value="distributionRecordForm.remark" show-count :maxlength="500"
- placeholder="请输入内容...." />
- </a-form-item>
- </a-col>
- </a-row>
- <a-row :gutter="30">
- <a-col :span="8">
- <a-form-item label="接收人" name="fileUrl">
- <a-upload-dragger v-model:fileList="fileList" name="file" :action="UploadUrl" @change="fileChange"
- accept=".xls,.xlsx">
- <p class="ant-upload-drag-icon">
- <inbox-outlined></inbox-outlined>
- </p>
- <template v-if="distributionRecordForm.fileUrl">
- <span class="fontsize14">{{ distributionRecordForm.fileUrl }}</span>
- </template>
- <template v-else>
- <p class="fontsize14">点击或将文件拖拽到这里上传,或者 <span style="color: #018FFB;">点击上传</span> </p>
- </template>
- </a-upload-dragger>
- <div class="dis a-c">
- <a-button type="link" @click="downloadTemplate">下载模版</a-button>
- <span class="fontsize14">仅允许导入“xls”或“xlsx”格式文件!最多导入1500人 </span>
- </div>
- <!-- 导入提示 -->
- <div class="importPrompt" v-if="fileresult.failRows">
- <div class="dis a-c">
- <InfoCircleOutlined style="font-size: 18px;color: #FAA21E;" />
- <span class="fontsize14 ml-1">您将导入 <span style="color: #018FFB;">{{ fileresult.totalRows }}</span>
- 条数据,其中 <span style="color: #018FFB;">{{ fileresult.successRows }}</span> 条正常导入;<span
- style="color: #FF4545;">{{
- fileresult.failRows }}</span>
- 条不符合要求无法导入</span>
- </div>
- <a-button type="link" @click="downloadFailedFile">下载导入失败文件</a-button>
- </div>
- </a-form-item>
- </a-col>
- </a-row>
- </div>
- <div class="card-header dis a-c mb-2">
- <div class="link"></div>
- <span>权益礼包</span>
- </div>
- <a-table :dataSource="distributionRecordForm.rightsList" size="small" :columns="Columns" :pagination="false"
- rowClassName="rowClassName">
- <template #bodyCell="{ column, record, index }">
- <template v-if="column.dataIndex === 'operation'">
- <a-button type="link" @click="rightsListAdd(column, record)">添加</a-button>
- <a-button type="link" @click="rightsListDel(column, record, index)" :disabled="index === 0">删除</a-button>
- </template>
- <template v-if="column.dataIndex === 'rightsContentName'">
- <a-select v-model:value="record.rightsContentId" placeholder="权益搜索" style="width: 300px"
- :options="entitlementPackages" :field-names="{ label: 'rightsContentName', value: 'rightsContentId' }">
- <template #dropdownRender>
- <div class="benefit">
- <div class="header dis a-c j-s">
- <span style="width: 50%;">权益名称</span>
- <span style="width: 25%;">类型</span>
- <span style="width: 25%;">采购价</span>
- </div>
- <div class="custom-options">
- <div v-for="item in entitlementPackages" :key="item.rightsContentId"
- class="option-item dis a-c j-s" @click="handleSelect(item, index)">
- <span style="width: 50%;">{{ item.rightsContentName }}</span>
- <span style="width: 25%;">{{ item.rightsContentType == 1 ? '单独权益' : '权益包' }}</span>
- <span style="width: 25%;">{{ item.settlePrice || 0 }}元</span>
- </div>
- </div>
- </div>
- </template>
- </a-select>
- </template>
- <template v-if="column.dataIndex === 'rightsType'">
- <span v-if="record.rightsType == '1'">单独权益</span>
- <span v-else-if="record.rightsType == '2'">权益包</span>
- <span v-else></span>
- </template>
- <template v-if="column.dataIndex === 'rightsCount'">
- <a-input-number v-model:value="record.rightsCount" style="width: 100%" allowClear placeholder="请输入权益数量" />
- </template>
- <template v-if="column.dataIndex === 'totalPrice'">
- <span>{{ Decimal(record.settlePrice || 0).times(record.rightsCount || 0) }}元</span>
- </template>
- </template>
- </a-table>
- </a-form>
- </div>
- <!-- 操作栏 -->
- <div class="footer flex a-c j-c">
- <a-button @click="onCancel">取消</a-button>
- <a-button @click="onSubmit" style="margin-left: 40px" type="primary">保存</a-button>
- </div>
- </div>
- </template>
- <!-- 行为区域 -->
- <script lang='ts' setup>
- import { reactive, ref, onMounted } from 'vue';
- import type { UnwrapRef } from 'vue';
- import { useRouter, useRoute } from 'vue-router';
- import { InboxOutlined, InfoCircleOutlined, ExclamationCircleFilled } from '@ant-design/icons-vue';
- import type { Rule, } from 'ant-design-vue/es/form';
- import * as businessConfigAPI from '/@/api/channel/businessConfig';
- import { type TreeSelectProps } from 'ant-design-vue';
- import * as distributionRecordAPI from '/@/api/channel/distributionRecord';
- import { message, Modal } from 'ant-design-vue';
- import { Decimal } from "decimal.js";
- import { useGlobSetting } from '/@/hooks/setting';
- import { createVNode } from 'vue';
- const globSetting = useGlobSetting();
- const baseUploadUrl = globSetting.uploadUrl;
- const UploadUrl = `${baseUploadUrl}/channel/grantRecord/uploadReceiverFile`; // 上传地址
- onMounted(() => {
- queryChannelOrg()//获取渠道机构数据
- })
- // 发放失败弹窗
- const failedToIssue = (failedFileUrl: string) => {
- Modal.confirm({
- title: '发放失败',
- okText: '忽略,确认发放',
- cancelText: '查看错误数据',
- content: '错误信息,本次发放权益的金额大于导入文件内的结算金额,请确认是否继续发放。',
- icon: createVNode(ExclamationCircleFilled, { style: 'color: #ff4d4f' }),
- onOk: () => {
- // 处理发放失败逻辑
- console.log(distributionRecordForm)
- return;
- distributionRecordAPI.addDistributionRecord(distributionRecordForm).then(res => {
- if (res.code === 200) {
- message.success('发放记录已保存');
- } else {
- message.error(res.message || '发放失败记录保存失败');
- }
- });
- },
- onCancel: () => {
- let Url = 'E:/workspace/opt/upFiles' + '/' + failedFileUrl;
- // 处理查看错误数据逻辑
- window.open(Url);
- },
- });
- }
- interface FormState {
- [key: string]: any;//默认全类型
- }
- // 校验规则弹窗
- const fileList = ref([]);//
- const formRef = ref();
- const treeData = ref<TreeSelectProps['treeData']>([]);//渠道机构数据
- const fileresult = ref<FormState>({});//文件上传后数据
- const labelCol = { style: { width: '150px' } };
- const entitlementPackages = ref();//权益礼包列表数据
- // 业务配置表单
- const distributionRecordForm: UnwrapRef<FormState> = reactive({
- institutionId: '',//机构id
- grantUserName: '',//联系人
- grantUserPhone: '',//联系人电话
- remark: '',//备注
- fileUrl: '',//接收人文件url
- failedFileUrl: '',//发放失败文件url
- rightsList: [
- {
- rightsContentId: "",//权益id
- rightsContentName: "",//权益名称
- rightsCount: 1,//权益数量
- rightsType: null,//权益类型
- settlePrice: "",//结算价
- totalPrice: "",//总价
- }
- ],//权益礼包
- });
- const distributionRecordFormRules: Record<string, Rule[]> = {
- institutionId: [
- { required: true, message: '请选择合作渠道机构', trigger: 'change' },
- ],
- grantUserName: [
- { required: true, message: '联系人姓名必填', trigger: 'blur' },
- ],
- grantUserPhone: [
- { required: true, message: '联系人手机号必填', trigger: 'blur' },
- {
- pattern: /^[0-9]+$/,
- message: '请输入正确手机号',
- },
- {
- min: 11,
- max: 11,
- message: '请输入11位手机号',
- },
- ],
- fileUrl: [
- { required: true, message: '请上传发放人群', trigger: 'blur' },
- ],
- };
- const Columns = [
- {
- title: '操作',
- dataIndex: 'operation',
- key: 'operation',
- align: "center",
- width: 200,
- },
- {
- title: '权益名称',
- dataIndex: 'rightsContentName',
- key: 'rightsContentName',
- align: "center",
- },
- {
- title: '权益类型',
- dataIndex: 'rightsType',
- key: 'rightsType',
- width: 200,
- align: "center"
- },
- {
- title: '结算价',
- dataIndex: 'settlePrice',
- key: 'settlePrice',
- align: "center",
- width: 200,
- },
- {
- title: '数量',
- dataIndex: 'rightsCount',
- key: 'rightsCount',
- align: "center",
- width: 200,
- },
- {
- title: '总价',
- dataIndex: 'totalPrice',
- key: 'totalPrice',
- align: "center",
- width: 200,
- },
- ]
- const onSubmit = () => {
- formRef.value.validate().then(() => {
- // 校验通过,提交表单数据
- console.log('表单数据:', distributionRecordForm);
- distributionRecordAPI.validateBeforeSubmit(distributionRecordForm).then(res => {
- if (res.code === 200) {
- if (res.result.success) {
- distributionRecordAPI.addDistributionRecord(distributionRecordForm).then(res => {
- if (res.code === 200) {
- message.success('发放成功');
- } else {
- message.error(res.message || '发放失败');
- }
- })
- } else {
- let Url = 'E:/workspace/opt/upFiles' + '/' + res.result.failedFileUrl;
- distributionRecordForm.failedFileUrl = res.result.failedFileUrl;
- failedToIssue(Url)
- }
- } else {
- message.error(res.message || '校验失败');
- }
- })
- }).catch(() => {
- // 校验不通过,处理错误逻辑
- console.log('校验失败');
- });
- }
- const handleSelect = (val: any, index: number) => {
- Object.assign(distributionRecordForm.rightsList[index], val)
- distributionRecordForm.rightsList[index].rightsType = val.rightsContentType
- };
- // 添加权益
- const rightsListAdd = (column, record) => {
- console.log(record)
- if (distributionRecordForm.rightsList.length >= 20) {
- message.error('最多添加20个权益')
- return
- } else {
- distributionRecordForm.rightsList.push({
- rightsContentId: "",
- rightsCount: 1,//权益数量
- rightsType: "",//权益类型
- })
- }
- }
- // 删除权益
- const rightsListDel = (column, record, index) => {
- distributionRecordForm.rightsList.splice(index, 1)
- }
- // 机构改变时查询权益
- const institutionChange = (val: string) => {
- getEntitlementPackages()
- };
- const getEntitlementPackages = () => {
- distributionRecordAPI.getChannelRightsByInstitution({
- institutionId: distributionRecordForm.institutionId,
- name: "",
- }).then(res => {
- if (res.code === 200) {
- entitlementPackages.value = res.result
- } else {
- message.error(res.msg || '权益查询失败');
- }
- })
- }
- // 获取业务配置渠道机构
- const queryChannelOrg = () => {
- businessConfigAPI.getChannelDeptList().then((res) => {
- if (res.code == 200) {
- treeData.value = res.result
- }
- });
- }
- // 文件上传
- const fileChange = async (info) => {
- if (info.file.status === 'done') {
- if (info.file.response.code == '200') {
- message.success(info.file.response.message);//文件上传成功
- fileresult.value = info.file.response.result;
- // let url= import.meta.env.VITE_GLOB_DOMAIN_URL + '/' + info.file.response.result.fileUrl;
- let fileUrl = 'E:/workspace/opt/upFiles' + '/' + info.file.response.result.fileUrl;
- let failedFileUrl = 'E:/workspace/opt/upFiles' + '/' + info.file.response.result.failedFileUrl;
- distributionRecordForm.fileUrl = fileUrl;
- distributionRecordForm.failedFileUrl = failedFileUrl;
- } else {
- message.error(info.file.response.message);//文件上传失败
- return
- }
- }
- }
- const onCancel = () => {
- window.close();
- }
- // 下载模版
- const downloadTemplate = () => {
- window.open(
- 'https://life.baoxianzhanggui.com/locallive-pro-java/channel/receiver/模板.xlsx',
- );
- }
- const downloadFailedFile = () => {
- window.open(
- distributionRecordForm.failedFileUrl,
- );
- }
- </script>
- <!-- 样式区域 -->
- <style lang='less' scoped>
- .body {
- padding: 10px 0px;
- box-sizing: border-box;
- height: 100%;
- .card {
- padding: 0 24px;
- box-sizing: border-box;
- background-color: #fff;
- border-radius: 4px;
- overflow-y: auto;
- height: calc(100vh - 192px);
- }
- }
- // 底部布局
- .footer {
- position: fixed;
- bottom: 0;
- right: 0;
- background: #fff;
- width: calc(100vw - 210px);
- height: 60px;
- padding: 10px 30px;
- box-sizing: border-box;
- >span {
- font-size: 16px;
- color: #1890FF;
- }
- }
- .card-header {
- padding: 20px 0;
- box-sizing: border-box;
- .link {
- width: 3px;
- height: 20px;
- border-radius: 0 5px 5px 0;
- background-color: #018FFB;
- margin-right: 7px;
- }
- font-size: 20px;
- color: #333;
- font-weight: bold;
- border-bottom: 1px solid #E5E5E5;
- }
- .card-Radio-container {
- gap: 0 24px;
- .card-Radio {
- position: relative;
- width: max-content;
- padding: 16px;
- box-sizing: border-box;
- background: #FFFFFF;
- border-radius: 4px 4px 4px 4px;
- border: 2px solid #E5E5E5;
- cursor: pointer;
- .Method {
- font-size: 14px;
- color: #333;
- font-weight: bold;
- line-height: 1.4;
- margin-bottom: 4px;
- }
- .annotation {
- font-size: 14px;
- color: #999;
- }
- .anticon-check-circle {
- position: absolute;
- top: 7px;
- right: 7px;
- font-size: 21px;
- color: #018FFB;
- }
- }
- .card-Radio-active {
- border: 2px solid #80C7FD;
- }
- }
- .color-preview {
- width: 120px;
- padding: 3px 10px;
- box-sizing: border-box;
- border-radius: 4px 4px 4px 4px;
- border: 1px solid #E5E5E5;
- .colorBlock {
- width: 16px;
- height: 16px;
- }
- span {
- font-size: 14px;
- color: #333;
- margin-left: 4px;
- }
- }
- .text {
- font-size: 14px;
- color: #999;
- }
- .w250 {
- width: 250px;
- }
- .fontsize14 {
- font-size: 14px;
- color: #333;
- }
- .table {
- width: 800px;
- }
- .merchantSupplier {
- padding: 6px 10px;
- box-sizing: border-box;
- background: #E9F4FF;
- border-radius: 2px 2px 2px 2px;
- width: auto;
- font-size: 14px;
- color: #018FFB;
- }
- .received {
- margin-left: 160px;
- }
- .importPrompt {
- background: #FFFAEF;
- border-radius: 4px 4px 4px 4px;
- border: 1px solid #FAA21E;
- padding: 16px;
- box-sizing: border-box;
- }
- .benefit {
- .header {
- padding: 4px;
- box-sizing: border-box;
- background: #F7F7F9;
- border-radius: 4px 4px 0px 0px;
- font-size: 14px;
- color: #333;
- font-weight: bold;
- border: 1px solid #EEEEEE;
- text-align: center;
- }
- .custom-options {
- max-height: 200px;
- overflow-y: auto;
- }
- .option-item {
- padding: 8px 6px;
- width: 100%;
- border-radius: 4px;
- span {
- text-align: center;
- }
- }
- .option-item:hover {
- background-color: #F7F7F9;
- }
- }
- </style>
|