parent
8e63fe4b83
commit
7e291e6722
14 changed files with 1039 additions and 19 deletions
@ -0,0 +1,7 @@ |
|||||||
|
import axios from '@/utils/request'; |
||||||
|
// 保险
|
||||||
|
export const saveFund = async (data: Record<string, any>): Promise<any> => (await axios.post('/product/fundProducts/save', data)).data; |
||||||
|
export const batchDeletion = async (data: number[]): Promise<any> => (await axios.post(`/product/fundProducts/batchDeletion`, data)).data; |
||||||
|
export const fundProductList = async (data: Record<string, any>): Promise<any> => (await axios.post(`/product/fundProducts/fundProductList`, data)).data; |
||||||
|
export const findById = async (id: number): Promise<any> => (await axios.post(`/product/fundProducts/findById?id=${id}`)).data; |
||||||
|
export const getAListOfAShares = async (keyWord: string): Promise<any> => (await axios.post(`/product/aShares/data/getAListOfAShares?keyWord=${keyWord}`)).data; |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
@ -0,0 +1,596 @@ |
|||||||
|
<template> |
||||||
|
<div> |
||||||
|
<el-tabs v-model="curTab"> |
||||||
|
<el-tab-pane :label="id ? '产品要素' : '新增产品'" |
||||||
|
name="tab1"> |
||||||
|
<el-form label-width="100px" |
||||||
|
label-suffix=":" |
||||||
|
class="form" |
||||||
|
status-icon> |
||||||
|
<el-form-item label="基金名称" |
||||||
|
prop="fundName"> |
||||||
|
<el-input placeholder="取个有吸引力的产品名,限20字。" |
||||||
|
maxlength="20" |
||||||
|
v-model="form.fundName"></el-input> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="基金类型" |
||||||
|
prop="fundType"> |
||||||
|
<el-select v-model="form.fundType" |
||||||
|
placeholder="请选择"> |
||||||
|
<el-option v-for="item in config[1]?.subject?.itemList" |
||||||
|
:key="item" |
||||||
|
:label="item.options" |
||||||
|
:value="item.itemId" /> |
||||||
|
</el-select> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="募集规模"> |
||||||
|
<div> |
||||||
|
<el-input placeholder="请输入" |
||||||
|
v-model="form.fundraisingScale"> |
||||||
|
<template #append>万元</template> |
||||||
|
</el-input> |
||||||
|
</div> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="运作方式" |
||||||
|
prop="modeOfOperation"> |
||||||
|
<el-select v-model="form.modeOfOperation" |
||||||
|
placeholder="请选择"> |
||||||
|
<el-option v-for="item in config[3]?.subject?.itemList" |
||||||
|
:key="item" |
||||||
|
:label="item.options" |
||||||
|
:value="item.itemId" /> |
||||||
|
</el-select> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="持股配置"> |
||||||
|
<div class="flex-1"> |
||||||
|
<p class="">输入心仪的A股代码或名称,组建属于你的股票基金,比重合计必须为100%,最多配置10支股票。</p> |
||||||
|
<div class="flex"> |
||||||
|
<p class="field-name w-[300px] mr-32">股票</p> |
||||||
|
<p class="field-name w-[100px] mr-32">比重(%)</p> |
||||||
|
<div class="field-name"> |
||||||
|
<el-icon class="cursor-pointer" |
||||||
|
:size="16" |
||||||
|
color="#333" |
||||||
|
@click="addStock"> |
||||||
|
<Plus /> |
||||||
|
</el-icon> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div v-for="(item, i) in form.shareholdingAllocationsList" |
||||||
|
:key="i" |
||||||
|
class="flex items-center mb-2"> |
||||||
|
<div class="w-[300px] mr-32"> |
||||||
|
<el-select-v2 class="w-full" |
||||||
|
v-model="item.stockCode" |
||||||
|
filterable |
||||||
|
remote |
||||||
|
:remote-method="val => remoteMethod(val, item)" |
||||||
|
clearable |
||||||
|
:options="item.stocks" |
||||||
|
:loading="loading" |
||||||
|
placeholder="请输入A股代码或者名称" /> |
||||||
|
</div> |
||||||
|
<div class="w-[100px] mr-32"> |
||||||
|
<el-input placeholder="请输入" |
||||||
|
v-model="item.proportion"></el-input> |
||||||
|
</div> |
||||||
|
<div> |
||||||
|
<el-icon class="cursor-pointer" |
||||||
|
:size="16" |
||||||
|
color="#333" |
||||||
|
@click="delStock(i)"> |
||||||
|
<Minus /> |
||||||
|
</el-icon> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</el-form-item> |
||||||
|
<el-form-item label="费率配置"> |
||||||
|
<div class="flex-1"> |
||||||
|
<p class="mt-1 mb-2 text-base">确认份额时长。</p> |
||||||
|
<!-- 份额时长 --> |
||||||
|
<div class="flex items-center mb-3"> |
||||||
|
客户T时买入,T+ |
||||||
|
<el-input class="w-[100px] mx-2" |
||||||
|
placeholder="请输入" |
||||||
|
v-model="form.buyingDuration"></el-input> |
||||||
|
<el-select class="w-[100px] mr-2" |
||||||
|
v-model="form.buyingUnit" |
||||||
|
placeholder="请选择"> |
||||||
|
<el-option v-for="item in config[5]?.recordChildren[0]?.recordChildren[1]?.subject?.itemList" |
||||||
|
:key="item" |
||||||
|
:value="item.options" /> |
||||||
|
</el-select> |
||||||
|
确认申购份额期间,资金进入冻结账户。 |
||||||
|
</div> |
||||||
|
<div class="flex items-center"> |
||||||
|
客户T时卖出,T+ |
||||||
|
<el-input class="w-[100px] mx-2" |
||||||
|
placeholder="请输入" |
||||||
|
v-model="form.sellingTime"></el-input> |
||||||
|
<el-select class="w-[100px] mr-2" |
||||||
|
v-model="form.soldUnit" |
||||||
|
placeholder="请选择"> |
||||||
|
<el-option v-for="item in config[5]?.recordChildren[0]?.recordChildren[1]?.subject?.itemList" |
||||||
|
:key="item" |
||||||
|
:value="item.options" /> |
||||||
|
</el-select> |
||||||
|
确认赎回金额期间,资金进入冻结账户。 |
||||||
|
</div> |
||||||
|
|
||||||
|
<!-- 买入费率 --> |
||||||
|
<p class="mt-10 mb-2 text-xs text-[#ef3838]">买入费率(单笔费率应小于5.00%,5000元)</p> |
||||||
|
<div class="flex"> |
||||||
|
<p class="field-name w-[400px] mr-32">金额</p> |
||||||
|
<p class="field-name w-[100px] mr-32">费率</p> |
||||||
|
<div class="field-name"> |
||||||
|
<el-icon class="cursor-pointer" |
||||||
|
:size="16" |
||||||
|
color="#333" |
||||||
|
@click="addRatio(0)"> |
||||||
|
<Plus /> |
||||||
|
</el-icon> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div v-for="(item, i) in form.buySellRatioList0" |
||||||
|
:key="i" |
||||||
|
class="flex items-center mb-2"> |
||||||
|
<div class="w-[400px] mr-10"> |
||||||
|
<el-input v-if="i" |
||||||
|
class="w-[100px] mr-2" |
||||||
|
placeholder="请输入" |
||||||
|
disabled |
||||||
|
v-model="form.buySellRatioList0[i - 1].input2"></el-input> |
||||||
|
<el-input v-else |
||||||
|
class="w-[100px] mr-2" |
||||||
|
placeholder="请输入" |
||||||
|
disabled |
||||||
|
v-model="item.input1"></el-input> |
||||||
|
{{ i ? '万' : ' ' }} |
||||||
|
<span class="mx-2"> |
||||||
|
<= 买入金额</span> |
||||||
|
<template v-if="i !== form.buySellRatioList0.length - 1"> |
||||||
|
< |
||||||
|
<el-input class="w-[100px] mx-2" |
||||||
|
placeholder="请输入" |
||||||
|
v-model="item.input2"></el-input> |
||||||
|
万 |
||||||
|
</template> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="mr-32"> |
||||||
|
<el-input class="w-[100px] mr-2" |
||||||
|
placeholder="请输入" |
||||||
|
v-model="item.rate"></el-input> |
||||||
|
<el-select class="w-[80px]" |
||||||
|
v-model="item.rateUnit" |
||||||
|
placeholder="请选择"> |
||||||
|
<el-option v-for="item in units" |
||||||
|
:key="item" |
||||||
|
:value="item" /> |
||||||
|
</el-select> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div v-if="i"> |
||||||
|
<el-icon class="cursor-pointer" |
||||||
|
:size="16" |
||||||
|
color="#333" |
||||||
|
@click="delRatio(0, i)"> |
||||||
|
<Minus /> |
||||||
|
</el-icon> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="mt-5 text-xs text-[#7a7a7a]"> |
||||||
|
<p>申购计算:</p> |
||||||
|
<p class="my-2">净申购金额 = 申购金额 / (1 + 申购费用)</p> |
||||||
|
<p>申购费用 = 申购金额 - 净申购金额</p> |
||||||
|
<p class="mt-2">申购份额 = 净申购金额 / T时基金份额净值</p> |
||||||
|
</div> |
||||||
|
|
||||||
|
<!-- 运作费率 --> |
||||||
|
<p class="mt-10 mb-2 text-xs text-[#ef3838]">运作费率(单笔费率应小于5.00%)</p> |
||||||
|
<div class="flex"> |
||||||
|
<span class="w-[140px]">管理费</span> |
||||||
|
<el-input class="w-[100px] mr-2" |
||||||
|
placeholder="请输入" |
||||||
|
v-model="form.operationManagementRate"></el-input>% |
||||||
|
</div> |
||||||
|
<div class="flex my-2"> |
||||||
|
<span class="w-[140px]">托管费</span> |
||||||
|
<el-input class="w-[100px] mr-2" |
||||||
|
placeholder="请输入" |
||||||
|
v-model="form.operatingEscrowRate"></el-input>% |
||||||
|
</div> |
||||||
|
<div class="flex"> |
||||||
|
<span class="w-[140px]">销售服务费</span> |
||||||
|
<el-input class="w-[100px] mr-2" |
||||||
|
placeholder="请输入" |
||||||
|
v-model="form.operatingSalesServiceRates"></el-input>% |
||||||
|
</div> |
||||||
|
<div class="mt-5 text-xs text-[#7a7a7a]"> |
||||||
|
<p>运作费计算:</p> |
||||||
|
<p class="my-2">管理费 = (前一日的基金资产净值 x 管理费率)/ 365</p> |
||||||
|
<p>托管费 = (前一日的基金资产净值 x 管理费率)/ 365</p> |
||||||
|
<p class="mt-2">销售服务费 = (前一日的基金资产净值 x 管理费率)/ 365</p> |
||||||
|
</div> |
||||||
|
|
||||||
|
<!-- 赎回费率 --> |
||||||
|
<p class="mt-10 mb-2 text-xs text-[#ef3838]">赎回费率(单笔费率应小于5.00%,5000元)</p> |
||||||
|
<div class="flex"> |
||||||
|
<p class="field-name w-[600px] mr-32">持有时长</p> |
||||||
|
<p class="field-name w-[100px] mr-32">费率</p> |
||||||
|
<div class="field-name"> |
||||||
|
<el-icon class="cursor-pointer" |
||||||
|
:size="16" |
||||||
|
color="#333" |
||||||
|
@click="addRatio(1)"> |
||||||
|
<Plus /> |
||||||
|
</el-icon> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div v-for="(item, i) in form.buySellRatioList1" |
||||||
|
:key="i" |
||||||
|
class="flex items-center mb-2"> |
||||||
|
<div class="w-[600px] mr-10"> |
||||||
|
<el-input v-if="i" |
||||||
|
class="w-[100px] mr-2" |
||||||
|
placeholder="请输入" |
||||||
|
disabled |
||||||
|
v-model="form.buySellRatioList1[i - 1].input2"></el-input> |
||||||
|
<el-input v-else |
||||||
|
class="w-[100px] mr-2" |
||||||
|
placeholder="请输入" |
||||||
|
disabled |
||||||
|
v-model="item.input1"></el-input> |
||||||
|
|
||||||
|
<el-select class="w-[100px]" |
||||||
|
v-model="item.soldUnit1" |
||||||
|
placeholder="请选择"> |
||||||
|
<el-option v-for="item in times" |
||||||
|
:key="item" |
||||||
|
:value="item" /> |
||||||
|
</el-select> |
||||||
|
|
||||||
|
<span class="mx-2"> |
||||||
|
<= 持有时长</span> |
||||||
|
<template v-if="i !== form.buySellRatioList1.length - 1"> |
||||||
|
< |
||||||
|
<el-input class="w-[100px] mx-2" |
||||||
|
placeholder="请输入" |
||||||
|
v-model="item.input2"></el-input> |
||||||
|
|
||||||
|
<el-select class="w-[100px]" |
||||||
|
v-model="item.soldUnit2" |
||||||
|
placeholder="请选择"> |
||||||
|
<el-option v-for="item in times" |
||||||
|
:key="item" |
||||||
|
:value="item" /> |
||||||
|
</el-select> |
||||||
|
</template> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="mr-32"> |
||||||
|
<el-input class="w-[100px] mr-2" |
||||||
|
placeholder="请输入" |
||||||
|
v-model="item.rate"></el-input> |
||||||
|
<el-select class="w-[80px]" |
||||||
|
v-model="item.rateUnit" |
||||||
|
placeholder="请选择"> |
||||||
|
<el-option v-for="item in units" |
||||||
|
:key="item" |
||||||
|
:value="item" /> |
||||||
|
</el-select> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div> |
||||||
|
<el-icon class="cursor-pointer" |
||||||
|
:size="16" |
||||||
|
color="#333" |
||||||
|
@click="delRatio(1, i)"> |
||||||
|
<Minus /> |
||||||
|
</el-icon> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="mt-5 text-xs text-[#7a7a7a]"> |
||||||
|
<p>赎回计算:</p> |
||||||
|
<p class="my-2">赎回费用 = 赎回总额 x 赎回费率</p> |
||||||
|
<p>赎回金额 = 赎回总额 - 赎回费用</p> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</el-form-item> |
||||||
|
<div class="flex justify-end"> |
||||||
|
<div class="submit" |
||||||
|
@click="submit">完成</div> |
||||||
|
</div> |
||||||
|
</el-form> |
||||||
|
</el-tab-pane> |
||||||
|
</el-tabs> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { ref, reactive, computed, watch, onMounted, defineEmits } from 'vue'; |
||||||
|
import { ElMessage } from 'element-plus'; |
||||||
|
import { Plus, Minus } from '@element-plus/icons-vue'; |
||||||
|
import { insuranceProductDetails, addInsuranceProducts } from '@/api/insurance'; |
||||||
|
import { getAListOfAShares, saveFund } from '@/api/fund'; |
||||||
|
import { getProcessInformationBasedOnRoles, addOperation } from '@/api/judgment'; |
||||||
|
import { useRouter, useRoute } from 'vue-router'; |
||||||
|
import { handleId } from '@/utils/common'; |
||||||
|
import { getStatus } from '@/store/useProduct'; |
||||||
|
import Info from './Info.vue'; |
||||||
|
import Cookies from 'js-cookie'; |
||||||
|
|
||||||
|
const emit = defineEmits(['getList']); |
||||||
|
|
||||||
|
const router = useRouter(); |
||||||
|
const route = useRoute(); |
||||||
|
const id = computed(() => route.query.id); |
||||||
|
const projectId = +Cookies.get('sand-projectId'); |
||||||
|
const levelId = +Cookies.get('sand-level'); |
||||||
|
const curTab = ref<string>('tab1'); |
||||||
|
const config = ref<any[]>([]); |
||||||
|
const info = ref<Record<string, any>>(null); |
||||||
|
const units = ref<string[]>(['%', '元']); |
||||||
|
const times = ref<string[]>(['分钟', '天', '小时', '月']); |
||||||
|
const loading = ref<boolean>(false); |
||||||
|
const form = reactive({ |
||||||
|
checkPointId: levelId, |
||||||
|
projectId, |
||||||
|
buyingDuration: '', |
||||||
|
buyingUnit: '天', |
||||||
|
fundName: '', |
||||||
|
fundType: '', |
||||||
|
fundraisingScale: '', |
||||||
|
modeOfOperation: '', |
||||||
|
operatingEscrowRate: '', |
||||||
|
operatingSalesServiceRates: '', |
||||||
|
operationManagementRate: '', |
||||||
|
sellingTime: '', |
||||||
|
soldUnit: '天', |
||||||
|
buySellRatioList0: [ |
||||||
|
{ |
||||||
|
input1: '0', |
||||||
|
input2: '', |
||||||
|
rate: '', |
||||||
|
rateUnit: '%', |
||||||
|
type: 0, |
||||||
|
}, |
||||||
|
{ |
||||||
|
input1: '', |
||||||
|
input2: '', |
||||||
|
rate: '', |
||||||
|
rateUnit: '%', |
||||||
|
type: 0, |
||||||
|
}, |
||||||
|
], |
||||||
|
buySellRatioList1: [ |
||||||
|
{ |
||||||
|
input1: '0', |
||||||
|
input2: '', |
||||||
|
rate: '', |
||||||
|
rateUnit: '%', |
||||||
|
soldUnit1: '分钟', |
||||||
|
soldUnit2: '分钟', |
||||||
|
type: 1, |
||||||
|
}, |
||||||
|
{ |
||||||
|
input1: '', |
||||||
|
input2: '', |
||||||
|
rate: '', |
||||||
|
rateUnit: '%', |
||||||
|
soldUnit1: '分钟', |
||||||
|
soldUnit2: '分钟', |
||||||
|
type: 1, |
||||||
|
}, |
||||||
|
], |
||||||
|
shareholdingAllocationsList: [ |
||||||
|
{ |
||||||
|
latestPrice: '', |
||||||
|
proportion: '', |
||||||
|
stockCode: '', |
||||||
|
stockName: '', |
||||||
|
stocks: [], |
||||||
|
}, |
||||||
|
], |
||||||
|
}); |
||||||
|
|
||||||
|
// 配置项 |
||||||
|
const getConfig = async () => { |
||||||
|
const { process } = await getProcessInformationBasedOnRoles(1161); |
||||||
|
config.value = process; |
||||||
|
}; |
||||||
|
// 详情 |
||||||
|
const getDetail = async () => { |
||||||
|
if (id.value) { |
||||||
|
try { |
||||||
|
const { data } = await insuranceProductDetails(id.value); |
||||||
|
info.value = data; |
||||||
|
} finally { |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
// 新增持股 |
||||||
|
const addStock = () => { |
||||||
|
form.shareholdingAllocationsList.length < 10 |
||||||
|
? form.shareholdingAllocationsList.push({ |
||||||
|
latestPrice: '', |
||||||
|
proportion: '', |
||||||
|
stockCode: '', |
||||||
|
stockName: '', |
||||||
|
stocks: [], |
||||||
|
}) |
||||||
|
: ElMessage.error('持股最多不能超过10只!'); |
||||||
|
}; |
||||||
|
// 删除持股 |
||||||
|
const delStock = (i: number) => { |
||||||
|
form.shareholdingAllocationsList.length > 1 && form.shareholdingAllocationsList.splice(i, 1); |
||||||
|
}; |
||||||
|
// 查询股票 |
||||||
|
const remoteMethod = (query: string, item: Record<string, any>) => { |
||||||
|
if (query !== '') { |
||||||
|
loading.value = true; |
||||||
|
setTimeout(async () => { |
||||||
|
loading.value = false; |
||||||
|
const { aShares } = await getAListOfAShares(query); |
||||||
|
aShares.forEach((e) => { |
||||||
|
e.label = e.f14; |
||||||
|
e.value = e.f12; |
||||||
|
}); |
||||||
|
item.stocks = aShares; |
||||||
|
}, 200); |
||||||
|
} else { |
||||||
|
item.stocks = []; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
// 新增一行费率 |
||||||
|
const addRatio = (type: number) => { |
||||||
|
if (form['buySellRatioList' + type].length === 5) { |
||||||
|
ElMessage.error('规则最多只能添加5条!'); |
||||||
|
} else { |
||||||
|
const temp = { |
||||||
|
input1: '', |
||||||
|
input2: '', |
||||||
|
rate: '', |
||||||
|
rateUnit: '%', |
||||||
|
type, |
||||||
|
}; |
||||||
|
if (type) { |
||||||
|
temp.soldUnit1 = '分钟'; |
||||||
|
temp.soldUnit2 = '分钟'; |
||||||
|
} |
||||||
|
form['buySellRatioList' + type].push(temp); |
||||||
|
} |
||||||
|
}; |
||||||
|
// 删除一行费率 |
||||||
|
const delRatio = (type: number, i: number) => { |
||||||
|
form['buySellRatioList' + type].length > 1 && form['buySellRatioList' + type].splice(i, 1); |
||||||
|
}; |
||||||
|
|
||||||
|
watch( |
||||||
|
() => route.query, |
||||||
|
() => { |
||||||
|
getDetail(); |
||||||
|
}, |
||||||
|
{ |
||||||
|
immediate: true, |
||||||
|
}, |
||||||
|
); |
||||||
|
|
||||||
|
const getId = (str: string): string | number => { |
||||||
|
const result = config.value[5]?.recordChildren[0]?.recordChildren[1]?.subject?.itemList?.find((e) => e.options === str); |
||||||
|
return result?.itemId || ''; |
||||||
|
}; |
||||||
|
// 新增判分记录 |
||||||
|
const addRecord = async (data: Record<string, any>) => { |
||||||
|
const preIds = `1,${levelId},1161`; // 1,关卡id,角色(这个页面是基金产品经理新增产品) |
||||||
|
const rule = [ |
||||||
|
handleId(1162, 308, data.fundName, preIds + ',1162', 3), |
||||||
|
handleId(1163, 309, 764, preIds + ',1163', 1), |
||||||
|
handleId(1164, 310, data.fundraisingScale, preIds + ',1164', 3), |
||||||
|
handleId(1165, 311, 765, preIds + ',1165', 1), |
||||||
|
]; |
||||||
|
|
||||||
|
const stockId = 1167; |
||||||
|
data.shareholdingAllocationsList.forEach((e, i) => { |
||||||
|
rule.push(handleId(1177, 312, e.stockName, `${preIds},1166,${stockId + i},1177`, 3)); |
||||||
|
rule.push(handleId(1178, 313, e.proportion + '%', `${preIds},1166,${stockId + i},1178`, 3)); |
||||||
|
}); |
||||||
|
rule.push( |
||||||
|
handleId(1181, 314, data.buyingDuration, preIds + ',1179,1180,1181', 3), |
||||||
|
handleId(1182, 315, getId(data.buyingUnit), preIds + ',1179,1180,1182', 3), |
||||||
|
handleId(1184, 314, data.sellingTime, preIds + ',1179,1183,1184', 3), |
||||||
|
handleId(1185, 315, getId(data.soldUnit), preIds + ',1179,1183,1185', 3), |
||||||
|
); |
||||||
|
|
||||||
|
// 处理买入费率 |
||||||
|
const buyId = 1187; |
||||||
|
data.buySellRatioList0.forEach((e, i) => { |
||||||
|
e.amountOrDuration && rule.push(handleId(1192, 316, e.amountOrDuration, `${preIds},1179,1186,${buyId + i},1192`, 3)); |
||||||
|
e.rate && rule.push(handleId(1193, 318, e.rate + e.rateUnit, `${preIds},1179,1186,${buyId + i},1193`, 3)); |
||||||
|
}); |
||||||
|
|
||||||
|
// 处理赎回费率 |
||||||
|
const sellId = 1200; |
||||||
|
data.buySellRatioList1.forEach((e, i) => { |
||||||
|
e.amountOrDuration && rule.push(handleId(1205, 314, e.amountOrDuration, `${preIds},1179,1199,${sellId + i},1205`, 3)); |
||||||
|
e.rate && rule.push(handleId(1206, 318, e.rate + e.rateUnit, `${preIds},1179,1199,${sellId + i},1206`, 3)); |
||||||
|
}); |
||||||
|
|
||||||
|
rule.push( |
||||||
|
handleId(1196, 319, data.operationManagementRate + '%', preIds + ',1179,1195,1196', 3), |
||||||
|
handleId(1197, 320, data.operatingEscrowRate + '%', preIds + ',1179,1195,1197', 3), |
||||||
|
handleId(1198, 321, data.operatingSalesServiceRates + '%', preIds + ',1179,1195,1198', 3), |
||||||
|
); |
||||||
|
|
||||||
|
await addOperation({ |
||||||
|
checkpointId: levelId, |
||||||
|
parentId: preIds, |
||||||
|
lcJudgmentRuleReq: rule, |
||||||
|
projectId, |
||||||
|
}); |
||||||
|
}; |
||||||
|
// 提交 |
||||||
|
const submit = async () => { |
||||||
|
try { |
||||||
|
const param = JSON.parse(JSON.stringify(form)); |
||||||
|
|
||||||
|
if (!param.fundName) return ElMessage.error('请输入保险名称'); |
||||||
|
if (!param.fundType) return ElMessage.error('请选择基金类型'); |
||||||
|
if (!param.fundraisingScale) return ElMessage.error('请输入募集规模'); |
||||||
|
if (!param.modeOfOperation) return ElMessage.error('请选择运作方式'); |
||||||
|
if (!param.shareholdingAllocationsList.length || !param.shareholdingAllocationsList.filter((e) => e.stockCode).length) return ElMessage.error('请配置持股'); |
||||||
|
|
||||||
|
// 计算持股权重是否等于100 |
||||||
|
let sum = 0; |
||||||
|
param.shareholdingAllocationsList.forEach((e) => { |
||||||
|
if (e.stockCode && e.proportion) { |
||||||
|
sum += +e.proportion; |
||||||
|
} |
||||||
|
}); |
||||||
|
if (sum !== 100) return ElMessage.error('持股权重总和需等于100,请重新配置'); |
||||||
|
if (!param.buyingDuration || !param.sellingTime) return ElMessage.error('请输入份额时长'); |
||||||
|
if (!param.operationManagementRate) return ElMessage.error('请输入管理费'); |
||||||
|
if (!param.operatingEscrowRate) return ElMessage.error('请输入托管费'); |
||||||
|
if (!param.operatingSalesServiceRates) return ElMessage.error('请输入销售服务费'); |
||||||
|
|
||||||
|
// 持股配置处理 |
||||||
|
param.shareholdingAllocationsList.forEach((e) => { |
||||||
|
if (e.stockCode) { |
||||||
|
const item = e.stocks.find((n) => n.f12 === e.stockCode); |
||||||
|
e.stockName = item.f14; |
||||||
|
e.latestPrice = item.f18; |
||||||
|
delete e.stocks; |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
// 处理费率 |
||||||
|
param.buySellRatioList0.forEach((e, i) => { |
||||||
|
e.amountOrDuration = i ? param.buySellRatioList0[i - 1].input2 : e.input1; |
||||||
|
if (i !== param.buySellRatioList0.length - 1) e.amountOrDuration += `-${e.input2}万`; |
||||||
|
}); |
||||||
|
param.buySellRatioList1.forEach((e, i) => { |
||||||
|
e.amountOrDuration = i ? param.buySellRatioList1[i - 1].input2 + param.buySellRatioList1[i - 1].soldUnit2 : e.input1; |
||||||
|
if (i !== param.buySellRatioList1.length - 1) e.amountOrDuration += `-${e.input2}${e.soldUnit2}`; |
||||||
|
}); |
||||||
|
param.buySellRatioList = [...param.buySellRatioList0, ...param.buySellRatioList1]; |
||||||
|
|
||||||
|
const recordParam = JSON.parse(JSON.stringify(param)); |
||||||
|
delete param.buySellRatioList0; |
||||||
|
delete param.buySellRatioList1; |
||||||
|
await saveFund(param); |
||||||
|
addRecord(recordParam); |
||||||
|
ElMessage.success('提交成功!'); |
||||||
|
emit('getList', 1); |
||||||
|
} finally { |
||||||
|
} |
||||||
|
}; |
||||||
|
onMounted(() => { |
||||||
|
getConfig(); |
||||||
|
}); |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
@import url(../../../styles/form.scss); |
||||||
|
</style> |
@ -0,0 +1,137 @@ |
|||||||
|
<template> |
||||||
|
<div class="block flex" |
||||||
|
style="padding-top: 0"> |
||||||
|
<div class="left w-[241px] min-w-[241px] pr-5 py-4"> |
||||||
|
<div class="flex justify-center items-center py-2 mb-3 text-sm text-[#006BFF] bg-[rgba(0,107,255,0.1)] border border-solid border-[#006BFF] rounded-[10px] cursor-pointer" |
||||||
|
@click="toAdd"> |
||||||
|
<el-icon class="mr-1" |
||||||
|
:size="16" |
||||||
|
color="#006BFF"> |
||||||
|
<Plus /> |
||||||
|
</el-icon> |
||||||
|
新增产品 |
||||||
|
</div> |
||||||
|
<div class="flex justify-end mb-4"> |
||||||
|
<img src="@/assets/images/fold.png" |
||||||
|
alt="" |
||||||
|
class="cursor-pointer" |
||||||
|
@click="toList" /> |
||||||
|
</div> |
||||||
|
<ul class="products"> |
||||||
|
<li v-for="(item, i) in list" |
||||||
|
:key="i" |
||||||
|
:class="{ active: item.id === id }" |
||||||
|
@click="switchProduct(item.id)"> |
||||||
|
<el-popconfirm title="您确定删除吗?" |
||||||
|
@confirm="handleDelete(item.id)"> |
||||||
|
<template #reference> |
||||||
|
<img src="@/assets/images/trash.png" |
||||||
|
alt="" |
||||||
|
class="del" /> |
||||||
|
</template> |
||||||
|
</el-popconfirm> |
||||||
|
|
||||||
|
<h6>{{ item.fundName }}</h6> |
||||||
|
<p class="type">{{ item.fundraisingScale }}万募集规模</p> |
||||||
|
<p class="type">买入费率{{ item.buying }},赎回费率{{ item.sale }}</p> |
||||||
|
<p class="date">创建日期:{{ item.createTime.split(' ')[0] }}</p> |
||||||
|
</li> |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
<div class="right flex-1 px-5 pt-2"> |
||||||
|
<detail v-if="action === 'detail'"></detail> |
||||||
|
<add v-else-if="action === 'add'" |
||||||
|
@getList="getList"></add> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { computed, onMounted, ref, watch } from 'vue'; |
||||||
|
import { ElMessage } from 'element-plus'; |
||||||
|
import { Plus } from '@element-plus/icons-vue'; |
||||||
|
import { fundProductList, batchDeletion } from '@/api/fund'; |
||||||
|
import { useRouter, useRoute } from 'vue-router'; |
||||||
|
import Detail from './Detail.vue'; |
||||||
|
import Add from './Add.vue'; |
||||||
|
import Cookies from 'js-cookie'; |
||||||
|
|
||||||
|
const router = useRouter(); |
||||||
|
const route = useRoute(); |
||||||
|
const action = ref<any>(''); |
||||||
|
const projectId = +Cookies.get('sand-projectId'); |
||||||
|
const levelId = +Cookies.get('sand-level'); |
||||||
|
|
||||||
|
const list = ref<Array<any>>([]); |
||||||
|
const loading = ref<boolean>(false); |
||||||
|
const id = computed(() => +route.query.id); |
||||||
|
// 列表 |
||||||
|
const getList = async (first: any) => { |
||||||
|
loading.value = true; |
||||||
|
try { |
||||||
|
const { data } = await fundProductList({ pageNum: 1, pageSize: 1000, checkPointId: levelId, projectId }); |
||||||
|
list.value = data.data.records; |
||||||
|
first && list.value.length && switchProduct(list.value[0].id); |
||||||
|
} finally { |
||||||
|
loading.value = false; |
||||||
|
} |
||||||
|
}; |
||||||
|
onMounted(() => { |
||||||
|
getList(); |
||||||
|
}); |
||||||
|
|
||||||
|
watch( |
||||||
|
route, |
||||||
|
(route: any) => { |
||||||
|
action.value = route.params.action; |
||||||
|
}, |
||||||
|
{ |
||||||
|
immediate: true, |
||||||
|
}, |
||||||
|
); |
||||||
|
// 产品切换 |
||||||
|
const switchProduct = (id: number) => { |
||||||
|
router.push(`/product/fund/detail?id=` + id); |
||||||
|
}; |
||||||
|
// 新增 |
||||||
|
const toAdd = () => { |
||||||
|
router.push(`/product/fund/add`); |
||||||
|
}; |
||||||
|
// 返回列表 |
||||||
|
const toList = () => { |
||||||
|
router.push(`/product/fund`); |
||||||
|
}; |
||||||
|
const handleDelete = async (id: number) => { |
||||||
|
await batchDeletion([id]); |
||||||
|
getList(1); |
||||||
|
ElMessage.success('删除成功!'); |
||||||
|
}; |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
.left { |
||||||
|
border-right: 1px solid #e9eff2; |
||||||
|
} |
||||||
|
.products { |
||||||
|
@apply max-h-[calc(100vh-205px)] pr-1 overflow-auto; |
||||||
|
li { |
||||||
|
@apply relative p-5 pt-7 mb-5 rounded-[10px] cursor-pointer border border-solid border-[transparent] bg-[url('@/assets/images/10.png')] bg-[length:100%_100%] bg-no-repeat; |
||||||
|
&.active { |
||||||
|
@apply border-[#CAE0FF]; |
||||||
|
} |
||||||
|
} |
||||||
|
.del { |
||||||
|
@apply absolute top-0 right-0; |
||||||
|
} |
||||||
|
h6 { |
||||||
|
@apply text-[#14436b]; |
||||||
|
} |
||||||
|
.type, |
||||||
|
.status { |
||||||
|
@apply my-[15px] text-sm text-[#333]; |
||||||
|
} |
||||||
|
.date { |
||||||
|
@apply text-sm text-[#8798a9]; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,21 @@ |
|||||||
|
<template> |
||||||
|
<div> |
||||||
|
<el-tabs v-model="curTab"> |
||||||
|
<el-tab-pane label="产品详情" |
||||||
|
name="tab1"> |
||||||
|
<info /> |
||||||
|
</el-tab-pane> |
||||||
|
</el-tabs> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { ref } from 'vue'; |
||||||
|
import Info from './Info.vue'; |
||||||
|
|
||||||
|
const curTab = ref<string>('tab1'); |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
@import url(../../../styles/form.scss); |
||||||
|
</style> |
@ -0,0 +1,105 @@ |
|||||||
|
<template> |
||||||
|
<div class="info mt-2"> |
||||||
|
<h2 class="text-center text-lg">{{ info.fundName }}</h2> |
||||||
|
<p class="text">基金类型:{{ info.fundType }}</p> |
||||||
|
<p class="text">基金规模:{{ info.fundraisingScale }}万元</p> |
||||||
|
<p class="text">运作方式:{{ info.modeOfOperation }}</p> |
||||||
|
<p class="text mt-10">持股配置:</p> |
||||||
|
<div class="text"> |
||||||
|
<div class="flex"> |
||||||
|
<p class="w-[130px] mr-32">股票</p> |
||||||
|
<p class="">比重(%)</p> |
||||||
|
</div> |
||||||
|
<div v-for="(item, i) in info.shareholdingAllocationsList" |
||||||
|
:key="item" |
||||||
|
class="flex"> |
||||||
|
<p class="w-[130px] mr-32">{{ item.stockName }}({{ item.stockCode }})</p> |
||||||
|
<p class="">{{ item.proportion }}</p> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<p class="text mt-10">费率配置:</p> |
||||||
|
<p class="text">客户T时买入,T+{{ info.buyingDuration }}{{ info.buyingUnit }}确认申购份额期间,资金进入冻结账户。</p> |
||||||
|
<p class="text">客户T时卖出,T+{{ info.sellingTime }}{{ info.soldUnit }}确认赎回金额期间,资金进入冻结账户。</p> |
||||||
|
|
||||||
|
<p class="text mt-5">买入费率</p> |
||||||
|
<div class="text"> |
||||||
|
<div class="flex"> |
||||||
|
<p class="w-[130px] mr-32">金额</p> |
||||||
|
<p class="">费率</p> |
||||||
|
</div> |
||||||
|
<div v-for="(item, i) in info.purchaseRateList" |
||||||
|
:key="item" |
||||||
|
class="flex"> |
||||||
|
<p class="w-[130px] mr-32">{{ item.amountOrDuration }}</p> |
||||||
|
<p class="">{{ item.rate }}{{ item.rateUnit |
||||||
|
}}</p> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<p class="text mt-5">管理费{{ info.operationManagementRate }}%</p> |
||||||
|
<p class="text">托管费{{ info.operatingEscrowRate }}%</p> |
||||||
|
<p class="text">销售服务费{{ info.operatingSalesServiceRates }}%</p> |
||||||
|
|
||||||
|
<p class="text mt-5">赎回费率</p> |
||||||
|
<div class="text"> |
||||||
|
<div class="flex"> |
||||||
|
<p class="w-[130px] mr-32">持有时长</p> |
||||||
|
<p class="">费率</p> |
||||||
|
</div> |
||||||
|
<div v-for="(item, i) in info.sellingRateList" |
||||||
|
:key="item" |
||||||
|
class="flex"> |
||||||
|
<p class="w-[130px] mr-32">{{ item.amountOrDuration }}</p> |
||||||
|
<p class="">{{ item.rate }}{{ item.rateUnit }}</p> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { ref, computed, watch, onMounted } from 'vue'; |
||||||
|
import { findById } from '@/api/fund'; |
||||||
|
import { useRouter, useRoute } from 'vue-router'; |
||||||
|
|
||||||
|
const router = useRouter(); |
||||||
|
const route = useRoute(); |
||||||
|
const id = computed(() => +route.query.id); |
||||||
|
const info = ref<Record<string, any>>({}); |
||||||
|
|
||||||
|
// 详情 |
||||||
|
const getDetail = async () => { |
||||||
|
if (id.value) { |
||||||
|
try { |
||||||
|
const { data } = await findById(id.value); |
||||||
|
info.value = data; |
||||||
|
} finally { |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
watch( |
||||||
|
() => route.query, |
||||||
|
() => { |
||||||
|
getDetail(); |
||||||
|
}, |
||||||
|
{ |
||||||
|
immediate: true, |
||||||
|
}, |
||||||
|
); |
||||||
|
</script> |
||||||
|
|
||||||
|
<style lang="scss" scoped> |
||||||
|
.info { |
||||||
|
.step-name { |
||||||
|
@apply mb-3 text-sm font-semibold text-[#006bff]; |
||||||
|
} |
||||||
|
.line { |
||||||
|
@apply flex mb-2; |
||||||
|
} |
||||||
|
.label { |
||||||
|
@apply mr-1 text-sm font-semibold text-[#333] leading-[32px]; |
||||||
|
} |
||||||
|
.text { |
||||||
|
@apply text-sm text-[#333] leading-[32px]; |
||||||
|
} |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,155 @@ |
|||||||
|
<template> |
||||||
|
<div class="block"> |
||||||
|
<div class="flex justify-between items-center mb-5"> |
||||||
|
<search v-model="params.fundName" |
||||||
|
@change="initList"></search> |
||||||
|
<div class="filter"> |
||||||
|
<div class="add-btn" |
||||||
|
@click="toAdd"> |
||||||
|
<img src="@/assets/images/plus.png" |
||||||
|
alt="" |
||||||
|
class="icon" /> |
||||||
|
新增产品 |
||||||
|
</div> |
||||||
|
<img src="@/assets/images/9.png" |
||||||
|
alt="" |
||||||
|
class="ml-4 cursor-pointer" |
||||||
|
@click="toCardList" /> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<el-table ref="table" |
||||||
|
v-loading="loading" |
||||||
|
:data="list" |
||||||
|
@sort-change="handleSort"> |
||||||
|
<el-table-column prop="fundName" |
||||||
|
label="基金名称" |
||||||
|
min-width="150"></el-table-column> |
||||||
|
<el-table-column prop="fundCode" |
||||||
|
label="基金代码" |
||||||
|
min-width="100"></el-table-column> |
||||||
|
<el-table-column prop="fundType" |
||||||
|
label="基金类型" |
||||||
|
min-width="100"></el-table-column> |
||||||
|
<el-table-column prop="fundraisingScale" |
||||||
|
label="募集规模" |
||||||
|
min-width="100"></el-table-column> |
||||||
|
<el-table-column prop="modeOfOperation" |
||||||
|
label="运作方式" |
||||||
|
min-width="100"></el-table-column> |
||||||
|
<el-table-column prop="buying" |
||||||
|
label="买入费率" |
||||||
|
min-width="120"></el-table-column> |
||||||
|
<el-table-column prop="sale" |
||||||
|
label="赎回费率" |
||||||
|
min-width="120"></el-table-column> |
||||||
|
<el-table-column prop="createTime" |
||||||
|
label="创建日期" |
||||||
|
width="180" |
||||||
|
sortable="custom"></el-table-column> |
||||||
|
<el-table-column label="操作" |
||||||
|
width="140"> |
||||||
|
<template #default="{ row }"> |
||||||
|
<el-popconfirm title="您确定删除吗?" |
||||||
|
@confirm.stop="handleDelete(row.id)"> |
||||||
|
<template #reference> |
||||||
|
<el-button type="text" |
||||||
|
size="small">删除</el-button> |
||||||
|
</template> |
||||||
|
</el-popconfirm> |
||||||
|
<el-button type="text" |
||||||
|
@click="toDetail(`/product/fund/detail`, row.id)" |
||||||
|
size="small">产品详情</el-button> |
||||||
|
</template></el-table-column> |
||||||
|
</el-table> |
||||||
|
<el-pagination v-model:currentPage="currentPage" |
||||||
|
v-model:pageSize="pageSize" |
||||||
|
:total="total" |
||||||
|
:page-sizes="pageSizes" |
||||||
|
:layout="pageLayout" |
||||||
|
@size-change="getList()" |
||||||
|
@current-change="getList()" |
||||||
|
small |
||||||
|
background |
||||||
|
class="px-3 py-2 justify-end"></el-pagination> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<script setup lang="ts"> |
||||||
|
import { computed, onMounted, ref, reactive, watch } from 'vue'; |
||||||
|
import { ElMessage } from 'element-plus'; |
||||||
|
import { pageSizes, pageLayout, toParams, resetParams } from '@/utils/common'; |
||||||
|
import { fundProductList, batchDeletion } from '@/api/fund'; |
||||||
|
import Search from '@/components/Search.vue'; |
||||||
|
import { useRouter, useRoute } from 'vue-router'; |
||||||
|
import Cookies from 'js-cookie'; |
||||||
|
import { productState, getExpertStatus, getStatus } from '@/store/useProduct'; |
||||||
|
|
||||||
|
const router = useRouter(); |
||||||
|
const route = useRoute(); |
||||||
|
const projectId = +Cookies.get('sand-projectId'); |
||||||
|
const levelId = +Cookies.get('sand-level'); |
||||||
|
const params = reactive({ |
||||||
|
createDateSort: '', |
||||||
|
fundName: '', |
||||||
|
checkPointId: levelId, |
||||||
|
projectId, |
||||||
|
}); |
||||||
|
const currentPage = ref<number>(1); |
||||||
|
const pageSize = ref<number>(10); |
||||||
|
const total = ref<number>(0); |
||||||
|
const table = ref<any>(); |
||||||
|
|
||||||
|
const list = ref<Array<any>>([]); |
||||||
|
const loading = ref<boolean>(false); |
||||||
|
const stop = () => {}; |
||||||
|
// 列表 |
||||||
|
const getList = async () => { |
||||||
|
loading.value = true; |
||||||
|
try { |
||||||
|
const { data } = await fundProductList({ pageNum: currentPage.value, pageSize: pageSize.value, ...toParams(params) }); |
||||||
|
list.value = data.data.records; |
||||||
|
total.value = data.data.total; |
||||||
|
} finally { |
||||||
|
loading.value = false; |
||||||
|
} |
||||||
|
}; |
||||||
|
// 重置列表 |
||||||
|
const initList = async () => { |
||||||
|
currentPage.value = 1; |
||||||
|
getList(); |
||||||
|
}; |
||||||
|
onMounted(() => { |
||||||
|
getList(); |
||||||
|
}); |
||||||
|
|
||||||
|
watch([params, () => route.query], initList); |
||||||
|
const handleSort = ({ column, prop, order }: { column: any; prop: string; order: string }) => { |
||||||
|
params.createDateSort = order === 'descending' ? 'desc' : order === 'ascending' ? 'asc' : ''; |
||||||
|
getList(); |
||||||
|
}; |
||||||
|
// 新增 |
||||||
|
const toAdd = () => { |
||||||
|
router.push({ |
||||||
|
path: `/product/fund/add`, |
||||||
|
}); |
||||||
|
}; |
||||||
|
// 产品详情 |
||||||
|
const toDetail = async (path: string, id: number) => { |
||||||
|
router.push({ |
||||||
|
path, |
||||||
|
query: { |
||||||
|
id, |
||||||
|
}, |
||||||
|
}); |
||||||
|
}; |
||||||
|
// 卡片模式 |
||||||
|
const toCardList = () => { |
||||||
|
router.push('/product/fund/detail'); |
||||||
|
}; |
||||||
|
|
||||||
|
const handleDelete = async (id: number) => { |
||||||
|
await batchDeletion([id]); |
||||||
|
getList(); |
||||||
|
ElMessage.success('删除成功!'); |
||||||
|
}; |
||||||
|
</script> |
Loading…
Reference in new issue