Commit a4139ef5 by sunchao

sfp项目转移

parent 94d94b1f
......@@ -316,5 +316,35 @@ export default {
//统一支付接口
unifiedPay(params){
return request(`${apiURL}/pay/unifiedPay`, "POST", params)
},
// 保单单利复利计算
irrAndSimpleCalcute(params) {
return request(`${baseURL}/api/sfp/calcuteUtil/irrAndSimpleCalcute`, "POST", params)
},
// 获取unionId
getWxUserInfo(params){
return request(`${baseURL}/api/getWxUserInfo`, "POST", params)
},
//增额寿和年金(单利复利)计算结果查询接口
queryIrrAndSimple(params){
return request(`${baseURL}/api/sfp/calcuteUtil/queryIrrAndSimple`, "POST", params)
},
//获取城市
provCityQry(params){
return request(`${baseURL}/api/metadata/provCityQry`, "POST", params)
},
//购房能力测算
housePurchasePlanAnalysis(params){
return request(`${baseURL}/api/sfp/calcuteUtil/housePurchasePlanAnalysis`, "POST", params)
},
// 各城市商品住宅销售价格查询接口
queryCommercialHousingPrice(params){
return request(`${baseURL}/api/sfp/calcuteConfig/queryCommercialHousingPrice`, "POST", params)
},
// 子女教育测算
educationEstimate(params){
return request(`${baseURL}/api/sfp/calcuteUtil/educationEstimate`, "POST", params)
}
}
......@@ -204,6 +204,47 @@ export default {
deviceType = '1';
}
return deviceType;
}
},
// 数据处理
action(data){ // 使用递归函数
// if(!(data?.length <= 0)){
// 等价于
if(!data || data.length <= 0){ // 递归的出口
return null;
}
return data.map(x => { // 循环数据
const model = { // 把后端返回过来的数据里面的键给替换成我想要的键
source: x,
text: x.provinceName ? x.provinceName : x.cityName,
value: x.cityId ? x.cityId : x.provinceId,
};
const children = this.action(x.citys); // 子级数据
if(children){ // 一直往下循环查找有没有children这个键,如果有就直接添加一个子级字段名,这个字段名就是存子级数据
model.children = children;
}
return model; // 返回这个数据
});
},
/*
num:源数据
digitNum:保留几位小数
type:向上(1)取
*/
formatFloat(num,digitNum=2,type=1){
if(num){
if(type===1){
const dataNum = (num * Math.pow(10, digitNum + 1) / Math.pow(10, digitNum + 1)).toString();
if(dataNum.indexOf('.')>-1){
return (Number(dataNum.slice(0, dataNum.indexOf('.') + digitNum + 1)) + 10 / Math.pow(10, digitNum + 1)).toFixed(digitNum)
}else{
return dataNum;
}
}else{
return (num * Math.pow(10, digitNum + 1) / Math.pow(10, digitNum + 1)).toFixed(digitNum)
}
}else{
return num;
}
},
}
\ No newline at end of file
......@@ -9,9 +9,9 @@
</u-button> -->
<!-- <u-button @click="clear" type="warning" :plain="true" :ripple="true" ripple-bg-color="#909399">清除
</u-button> -->
<view class="imgBox" style="margin-top: 20rpx;">
<!-- <view class="imgBox" style="margin-top: 20rpx;">
<image src="../../static/clear.png" @click="clear" mode="widthFix"></image>
</view>
</view> -->
<!-- <u-button @click="close" type="error" :plain="true" :ripple="true" ripple-bg-color="#909399">关闭
</u-button> -->
</view>
......@@ -43,7 +43,7 @@
};
},
props: ['showCanvas'],
emits: ['sendImage'],
emits: ['sendImage',],
methods: {
//清除签名的图片
obliterate() {
......
......@@ -34,7 +34,6 @@
},
methods: {
goDetail(item) {
console.log(item, 844)
if (item.isShow == true && item.isOpen == true) {
if (item.isTips == true) {
uni.showModal({
......
{
"name": "日期区间picker",
"version": "1.0.7",
"lockfileVersion": 2,
"lockfileVersion": 1,
"requires": true,
"packages": {
"": {
"name": "日期区间picker",
"version": "1.0.7",
"dependencies": {
"nanoid": "^4.0.0",
"vue-signature-pad": "^3.0.2"
}
},
"node_modules/@babel/parser": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz",
"integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==",
"peer": true,
"bin": {
"parser": "bin/babel-parser.js"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@vue/compiler-core": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.45.tgz",
"integrity": "sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A==",
"peer": true,
"dependencies": {
"@babel/parser": "^7.16.4",
"@vue/shared": "3.2.45",
"estree-walker": "^2.0.2",
"source-map": "^0.6.1"
}
},
"node_modules/@vue/compiler-dom": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz",
"integrity": "sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==",
"peer": true,
"dependencies": {
"@vue/compiler-core": "3.2.45",
"@vue/shared": "3.2.45"
}
},
"node_modules/@vue/compiler-sfc": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz",
"integrity": "sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q==",
"peer": true,
"dependencies": {
"@babel/parser": "^7.16.4",
"@vue/compiler-core": "3.2.45",
"@vue/compiler-dom": "3.2.45",
"@vue/compiler-ssr": "3.2.45",
"@vue/reactivity-transform": "3.2.45",
"@vue/shared": "3.2.45",
"estree-walker": "^2.0.2",
"magic-string": "^0.25.7",
"postcss": "^8.1.10",
"source-map": "^0.6.1"
}
},
"node_modules/@vue/compiler-ssr": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz",
"integrity": "sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ==",
"peer": true,
"dependencies": {
"@vue/compiler-dom": "3.2.45",
"@vue/shared": "3.2.45"
}
},
"node_modules/@vue/reactivity": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz",
"integrity": "sha512-PRvhCcQcyEVohW0P8iQ7HDcIOXRjZfAsOds3N99X/Dzewy8TVhTCT4uXpAHfoKjVTJRA0O0K+6QNkDIZAxNi3A==",
"peer": true,
"dependencies": {
"@vue/shared": "3.2.45"
}
},
"node_modules/@vue/reactivity-transform": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz",
"integrity": "sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ==",
"peer": true,
"dependencies": {
"@babel/parser": "^7.16.4",
"@vue/compiler-core": "3.2.45",
"@vue/shared": "3.2.45",
"estree-walker": "^2.0.2",
"magic-string": "^0.25.7"
}
},
"node_modules/@vue/runtime-core": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.45.tgz",
"integrity": "sha512-gzJiTA3f74cgARptqzYswmoQx0fIA+gGYBfokYVhF8YSXjWTUA2SngRzZRku2HbGbjzB6LBYSbKGIaK8IW+s0A==",
"peer": true,
"dependencies": {
"@vue/reactivity": "3.2.45",
"@vue/shared": "3.2.45"
}
},
"node_modules/@vue/runtime-dom": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz",
"integrity": "sha512-cy88YpfP5Ue2bDBbj75Cb4bIEZUMM/mAkDMfqDTpUYVgTf/kuQ2VQ8LebuZ8k6EudgH8pYhsGWHlY0lcxlvTwA==",
"peer": true,
"dependencies": {
"@vue/runtime-core": "3.2.45",
"@vue/shared": "3.2.45",
"csstype": "^2.6.8"
}
},
"node_modules/@vue/server-renderer": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.45.tgz",
"integrity": "sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g==",
"peer": true,
"dependencies": {
"@vue/compiler-ssr": "3.2.45",
"@vue/shared": "3.2.45"
},
"peerDependencies": {
"vue": "3.2.45"
}
},
"node_modules/@vue/shared": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.45.tgz",
"integrity": "sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==",
"peer": true
},
"node_modules/csstype": {
"version": "2.6.21",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz",
"integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==",
"peer": true
},
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"peer": true
},
"node_modules/magic-string": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz",
"integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==",
"peer": true,
"dependencies": {
"sourcemap-codec": "^1.4.8"
}
},
"node_modules/merge-images": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/merge-images/-/merge-images-1.2.0.tgz",
"integrity": "sha512-hEGvgnTdXr08uzGvEArxRsKpy7WmozM73YaSi4s5IYF4LxrhANpqfHaz9CgBZ5+0+s2NsjPnPdStz3aCc0Yulw=="
},
"node_modules/nanoid": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz",
"integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg==",
"bin": {
"nanoid": "bin/nanoid.js"
},
"engines": {
"node": "^14 || ^16 || >=18"
}
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
"peer": true
},
"node_modules/postcss": {
"version": "8.4.19",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz",
"integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
}
],
"peer": true,
"dependencies": {
"nanoid": "^3.3.4",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/postcss/node_modules/nanoid": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"peer": true,
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/signature_pad": {
"version": "3.0.0-beta.4",
"resolved": "https://registry.npmmirror.com/signature_pad/-/signature_pad-3.0.0-beta.4.tgz",
"integrity": "sha512-cOf2NhVuTiuNqe2X/ycEmizvCDXk0DoemhsEpnkcGnA4kS5iJYTCqZ9As7tFBbsch45Q1EdX61833+6sjJ8rrw=="
},
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/sourcemap-codec": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
"deprecated": "Please use @jridgewell/sourcemap-codec instead",
"peer": true
},
"node_modules/vue": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.2.45.tgz",
"integrity": "sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA==",
"peer": true,
"dependencies": {
"@vue/compiler-dom": "3.2.45",
"@vue/compiler-sfc": "3.2.45",
"@vue/runtime-dom": "3.2.45",
"@vue/server-renderer": "3.2.45",
"@vue/shared": "3.2.45"
}
},
"node_modules/vue-signature-pad": {
"version": "3.0.2",
"resolved": "https://registry.npmmirror.com/vue-signature-pad/-/vue-signature-pad-3.0.2.tgz",
"integrity": "sha512-o25o+lROfCmzASS2+fU8ZV801kV+D4/02zkZ+ez3NKeiUmbxW7kwlUf5oKQkvA+l7Ou9xGsGLsirBLch3jyX8A==",
"dependencies": {
"merge-images": "^1.1.0",
"signature_pad": "^3.0.0-beta.3"
},
"engines": {
"node": ">=12"
},
"peerDependencies": {
"vue": "^3.2.0"
}
}
},
"dependencies": {
"@babel/parser": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz",
"integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==",
"peer": true
},
"@vue/compiler-core": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.45.tgz",
"integrity": "sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A==",
"peer": true,
"requires": {
"@babel/parser": "^7.16.4",
"@vue/shared": "3.2.45",
"estree-walker": "^2.0.2",
"source-map": "^0.6.1"
}
},
"@vue/compiler-dom": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz",
"integrity": "sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==",
"peer": true,
"requires": {
"@vue/compiler-core": "3.2.45",
"@vue/shared": "3.2.45"
}
},
"@vue/compiler-sfc": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz",
"integrity": "sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q==",
"peer": true,
"requires": {
"@babel/parser": "^7.16.4",
"@vue/compiler-core": "3.2.45",
"@vue/compiler-dom": "3.2.45",
"@vue/compiler-ssr": "3.2.45",
"@vue/reactivity-transform": "3.2.45",
"@vue/shared": "3.2.45",
"estree-walker": "^2.0.2",
"magic-string": "^0.25.7",
"postcss": "^8.1.10",
"source-map": "^0.6.1"
}
},
"@vue/compiler-ssr": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz",
"integrity": "sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ==",
"peer": true,
"requires": {
"@vue/compiler-dom": "3.2.45",
"@vue/shared": "3.2.45"
}
},
"@vue/reactivity": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz",
"integrity": "sha512-PRvhCcQcyEVohW0P8iQ7HDcIOXRjZfAsOds3N99X/Dzewy8TVhTCT4uXpAHfoKjVTJRA0O0K+6QNkDIZAxNi3A==",
"peer": true,
"requires": {
"@vue/shared": "3.2.45"
}
},
"@vue/reactivity-transform": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz",
"integrity": "sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ==",
"peer": true,
"requires": {
"@babel/parser": "^7.16.4",
"@vue/compiler-core": "3.2.45",
"@vue/shared": "3.2.45",
"estree-walker": "^2.0.2",
"magic-string": "^0.25.7"
}
},
"@vue/runtime-core": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.45.tgz",
"integrity": "sha512-gzJiTA3f74cgARptqzYswmoQx0fIA+gGYBfokYVhF8YSXjWTUA2SngRzZRku2HbGbjzB6LBYSbKGIaK8IW+s0A==",
"peer": true,
"requires": {
"@vue/reactivity": "3.2.45",
"@vue/shared": "3.2.45"
}
},
"@vue/runtime-dom": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz",
"integrity": "sha512-cy88YpfP5Ue2bDBbj75Cb4bIEZUMM/mAkDMfqDTpUYVgTf/kuQ2VQ8LebuZ8k6EudgH8pYhsGWHlY0lcxlvTwA==",
"peer": true,
"requires": {
"@vue/runtime-core": "3.2.45",
"@vue/shared": "3.2.45",
"csstype": "^2.6.8"
}
},
"@vue/server-renderer": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.45.tgz",
"integrity": "sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g==",
"peer": true,
"requires": {
"@vue/compiler-ssr": "3.2.45",
"@vue/shared": "3.2.45"
}
},
"@vue/shared": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.45.tgz",
"integrity": "sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==",
"peer": true
},
"csstype": {
"version": "2.6.21",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz",
"integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==",
"peer": true
},
"estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"peer": true
},
"magic-string": {
"version": "0.25.9",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz",
"integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==",
"peer": true,
"echarts": {
"version": "5.4.1",
"resolved": "https://registry.npmmirror.com/echarts/-/echarts-5.4.1.tgz",
"integrity": "sha512-9ltS3M2JB0w2EhcYjCdmtrJ+6haZcW6acBolMGIuf01Hql1yrIV01L1aRj7jsaaIULJslEP9Z3vKlEmnJaWJVQ==",
"requires": {
"sourcemap-codec": "^1.4.8"
"tslib": "2.3.0",
"zrender": "5.4.1"
}
},
"merge-images": {
......@@ -418,69 +20,18 @@
},
"nanoid": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz",
"resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-4.0.0.tgz",
"integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg=="
},
"picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
"peer": true
},
"postcss": {
"version": "8.4.19",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz",
"integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==",
"peer": true,
"requires": {
"nanoid": "^3.3.4",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
"dependencies": {
"nanoid": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"peer": true
}
}
},
"signature_pad": {
"version": "3.0.0-beta.4",
"resolved": "https://registry.npmmirror.com/signature_pad/-/signature_pad-3.0.0-beta.4.tgz",
"integrity": "sha512-cOf2NhVuTiuNqe2X/ycEmizvCDXk0DoemhsEpnkcGnA4kS5iJYTCqZ9As7tFBbsch45Q1EdX61833+6sjJ8rrw=="
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"peer": true
},
"source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"peer": true
},
"sourcemap-codec": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
"peer": true
},
"vue": {
"version": "3.2.45",
"resolved": "https://registry.npmjs.org/vue/-/vue-3.2.45.tgz",
"integrity": "sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA==",
"peer": true,
"requires": {
"@vue/compiler-dom": "3.2.45",
"@vue/compiler-sfc": "3.2.45",
"@vue/runtime-dom": "3.2.45",
"@vue/server-renderer": "3.2.45",
"@vue/shared": "3.2.45"
}
"tslib": {
"version": "2.3.0",
"resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.3.0.tgz",
"integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
},
"vue-signature-pad": {
"version": "3.0.2",
......@@ -490,6 +41,14 @@
"merge-images": "^1.1.0",
"signature_pad": "^3.0.0-beta.3"
}
},
"zrender": {
"version": "5.4.1",
"resolved": "https://registry.npmmirror.com/zrender/-/zrender-5.4.1.tgz",
"integrity": "sha512-M4Z05BHWtajY2241EmMPHglDQAJ1UyHQcYsxDNzD9XLSkPDqMq4bB28v9Pb4mvHnVQ0GxyTklZ/69xCFP6RXBA==",
"requires": {
"tslib": "2.3.0"
}
}
}
}
......@@ -17,6 +17,7 @@
]
},
"dependencies": {
"echarts": "^5.4.1",
"nanoid": "^4.0.0",
"vue-signature-pad": "^3.0.2"
}
......
......@@ -410,6 +410,34 @@
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
},
{
"path": "sfp/index/index",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
},
{
"path": "sfp/housePurchase/housePurchase",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
},
{
"path": "sfp/childEdu/childEdu",
"style": {
"navigationBarTitleText": "",
"enablePullDownRefresh": false
}
},
{
"path": "sfp/dataImport/data-import",
"style": {
"topWindow": false,
"navigationBarTitleText": "批量数据计算"
}
}
],
// "tabBar": {
......
......@@ -121,7 +121,7 @@
}
.fixed {
position: fixed;
bottom: 0;
bottom: 60rpx;
left: 0;
right: 0;
height: 100rpx;
......
......@@ -24,9 +24,12 @@
<text class="page_mark">8/8</text>
</view>
<view class="signatureContent" v-if="!applyParam.personalSignOssPath">
<e-signature :style="{'width':'100vw','height':'80vh'}" :showCanvas="showCanvas" ref="signatureComponent" @sendImage="getImage"></e-signature>
<e-signature :style="{'width':'100vw','height':'80vh'}" :showCanvas="showCanvas" ref="signatureComponent" @sendImage="getImage" ></e-signature>
</view>
<image :src="applyParam.personalSignOssPath" mode="widthFix" v-if="applyParam.personalSignOssPath"></image>
<view class="imgBox" style="margin-top: 20rpx;">
<image src="../../static/clear.png" @click="clearImg" mode="widthFix"></image>
</view>
<view class="fixed" url="bank-card" @click="save()">
{{(this.applyParam.approvalStatus== 0 || this.applyParam.approvalStatus == 2)?'我自愿签订推广人合同书':'下一步'}}
</view>
......@@ -68,7 +71,16 @@
}else{
this.$refs.signatureComponent.finish()
}
},
clearImg(){
//0-未提交,1-待审核,2-审核未通过,3-审核通过
if((this.applyParam.personalSignOssPath && this.applyParam.approvalStatus == 2) ||
(this.applyParam.personalSignOssPath && this.applyParam.approvalStatus == 0)
){
this.applyParam.personalSignOssPath = null;
}else{
this.$refs.signatureComponent.clear();
}
},
queryById(id,userId){
api.queryById({id:id,userId:userId}).then((res)=>{
......@@ -134,6 +146,7 @@
background: #fff;
margin-top: 20rpx;
height: 100%;
position: relative;
}
.signature_action{
display: flex;
......@@ -141,4 +154,11 @@
margin-top: 20rpx;
uni-image{max-width: 120rpx;max-height: 120rpx;}
}
.imgBox{
position: absolute;
top: 75%;
left: 40%;
width: 120rpx;
height: 120rpx;
}
</style>
\ No newline at end of file
......@@ -390,6 +390,9 @@
box-shadow: 0px 0px 22px 0px rgba(0,0,0,0.1);
border-radius: 10rpx;
}
.uni-calendar{
padding-bottom: 50rpx;
}
.lineChartBox{
width: 100%;
.chartTips{
......
......@@ -30,7 +30,7 @@
</view>
</view>
<view class="paymentItem" @click="selectPaymentMethod(1)">
<view class="paymentItem" @click="selectPaymentMethod(1)" v-if="deviceType==3">
<view>
<i class="iconfont icon-py_weixinzhifu"></i>
<text>微信支付</text>
......@@ -39,6 +39,17 @@
<i class="iconfont icon-duihao"></i>
</view>
</view>
<!-- #ifdef APP-PLUS -->
<view class="paymentItem" @click="selectPaymentMethod(1)" >
<view>
<i class="iconfont icon-py_weixinzhifu"></i>
<text>微信支付</text>
</view>
<view class="selectRadio" :class="{'actived':paymentMethod===1}">
<i class="iconfont icon-duihao"></i>
</view>
</view>
<!-- #endif -->
</view>
<!-- 底部 -->
<view class="totalContent">
......@@ -200,13 +211,41 @@
if(this.paymentMethod==1){
// APP:微信app支付
// #ifdef APP-PLUS
api.wxAppPay(param).then(res=>{
param.paymentType = 1;
api.unifiedPay(param).then(res=>{
console.log(res)
this.paymentBtnDisabled = false;
})
// #endif
// #ifdef H5
param.paymentType = 2;
//deviceType:PC为1,移动端为2,微信为3
if(this.deviceType == 3){
//微信h5支付
console.log(this.$queue)
uni.login({
provider: 'weixin',
success: function (loginRes) {
console.log(loginRes)
// 登录成功
uni.getUserInfo({
provider: 'weixin',
success: function(info) {
alert(JSON.stringify(info))
param.openId=info.openId;
}
})
},
fail: function (err) {
// 登录授权失败
// err.code是错误码
}
});
}else{
//微信二维码支付
}
// #endif
}else if(this.paymentMethod==2){
......
......@@ -14,31 +14,31 @@ import MenuList from "@/components/menuList/menuList.vue"
minorMenuLists: [{
title: '房贷推销计算器',
icon: 'shareEcode',
link: '',
link: '/sfp/housePurchase/housePurchase',
isOpen: true,
isShow: true,
isTips: false,
},
{
title: '现金流计算器',
title: '子女教育计算器',
icon: 'card',
link: '',
isOpen: true,
isShow: true,
isTips: true,
},
{
title: '货币时间价值计算器',
icon: 'myCertify',
link: '',
link: '/sfp/childEdu/childEdu',
isOpen: true,
isShow: true,
isTips: false,
},
// {
// title: '货币时间价值计算器',
// icon: 'myCertify',
// link: '',
// isOpen: true,
// isShow: true,
// isTips: false,
// },
{
title: '保单利率计算器',
icon: 'myCertify',
link: '',
link: '/sfp/index/index',
isOpen: true,
isShow: true,
isTips: false,
......
{
"appid": "wx6f51ca088a97f1db",
"compileType": "miniprogram",
"libVersion": "2.28.1",
"packOptions": {
"ignore": [],
"include": []
},
"setting": {
"coverView": true,
"es6": true,
"postcss": true,
"minified": true,
"enhance": true,
"showShadowRootInWxmlPanel": true,
"packNpmRelationList": [],
"babelSetting": {
"ignore": [],
"disablePlugins": [],
"outputPath": ""
}
},
"condition": {},
"editorSetting": {
"tabIndent": "insertSpaces",
"tabSize": 2
},
"simulatorPluginLibVersion": {}
}
\ No newline at end of file
{
"description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html",
"projectname": "CFFP-HB",
"setting": {
"compileHotReLoad": true
}
}
\ No newline at end of file
.listContent .liBox{
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #E4E4E4;
padding: 16rpx 0;
font-size: 28rpx;
}
.listContent .multiline{
flex-direction: column;
justify-content: center;
align-items: flex-start;
}
.listContent .liBox >view:last-child{
display: flex;
align-items: center;
white-space: nowrap;
}
.multilineItem{
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
margin-bottom: 12rpx;
}
.selectBtnContent{
display: flex;
}
.selectBtnContent text{
position: relative;
width: 100rpx;
height: 50rpx;
text-align: center;
line-height: 50rpx;
position: relative;
border: 1px solid #FED597;
margin-right: 20rpx;
border-radius: 6rpx;
}
.selectBtnContent text.actived::after{
position: absolute;
content: '';
display: block;
bottom: 0;
right: 0;
border: 18rpx solid #FED495;
border-left-color: transparent;
border-top-color: transparent;
}
.selectBtnContent text.actived::before{
content: '√';
position: absolute;
display: block;
right: 0;
z-index: 1;
color: #fff;
bottom: -7px;
}
.listContent .planGradeRange{
flex-direction: column;
justify-content: center;
align-items: flex-start;
}
.listContent .planGradeRange > view:last-child{
display: flex;
align-items: center;
justify-content: center;
margin: 12rpx auto;
width: 100%;
}
.listContent view.planGradeRange > view:last-child text{
position: relative;
width: 80rpx;
height: 1px;
background-color: #E4E4E4;
margin: 0 10rpx;
}
.schoolingContent{
margin-top: 10px;
box-shadow: 0px 0px 6px 1px rgb(0 0 0 / 35%);
border-top-left-radius: 12rpx;
border-top-right-radius: 12rpx;
margin: 20rpx 10rpx;
}
.schoolingContent .liBox{
display: flex;
height: 80rpx;
justify-content: center;
align-items: center;
border-bottom: 1px solid #E4E4E4;
padding: 0 10rpx;
}
.schoolingContent .liBox:first-child{
background: linear-gradient(to right,#CEB07D,#FFDDA9);
color: #6B4000;
font-weight: bold;
}
.schoolingContent .liBox > view{
width: 0;
flex: 1;
height: 100%;
white-space: nowrap;
font-size: 24rpx;
border-right: 1rpx solid #E4E4E4;
display: flex;
justify-content: center;
align-items: center;
}
.schoolingContent .liBox > view:last-child{
border-right: none;
}
.settingButton{
border-radius: 8rpx;
background: #F7D295;
color: #6B4000;
padding: 10rpx 20rpx;
}
.summaryContent {
margin: 0 20rpx;
}
.successInfo,.failInfo,.suggestionInfo{
background-color: rgba(35,255,0,0.02);
padding: 20rpx 60rpx;
color: #333;
margin-top: 20rpx;
}
.failInfo{
background-color: #FFE6E6;
}
input{
text-align: right!important;
}
.dialogContainer{
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.35);
z-index: 2;
}
.dialogContent{
position: absolute;
left: 50%;
top: 30%;
transform: translateX(-50%);
width: 95%;
background-color: #fff;
border-radius: 10rpx;
padding: 20rpx 40rpx;
box-sizing: border-box;
}
.dialogContent .closeBtn{
text-align: right;
font-size: 56rpx;
}
.dialogContent .ulBox{
border-radius: 5rpx;
box-shadow: 0 0 10rpx 4rpx rgba(0,0,0,0.25);
margin-top: 20rpx;
}
.dialogContent .ulBox .liBox{
display: flex;
height: 80rpx;
border-bottom: 1rpx solid #E4E4E4;
color: #6B4000;
}
.dialogContent .ulBox .liBox:first-child{
background: linear-gradient(to right,#CEB07D,#FFDDA9);
}
.dialogContent .ulBox .liBox > view{
flex: 1;
text-align: center;
height: 100%;
align-items: center;
display: flex;
justify-content: center;
border-right: 1px solid #E4E4E4;
}
.dialogContent .ulBox .liBox > view:last-child{
border-right: none;
}
.dialogContent button{
margin-top: 40rpx;
background: linear-gradient(to bottom right,#CEB07D,#FFDDA9);
color: #6B4000;
border: none;
width: 50%;
font-weight: bold;
}
.dialogContainer .dialogContent input,.schoolingContent .liBox > view input{
text-align: center!important;
padding-left: 10rpx;
}
\ No newline at end of file
<template>
<view>
<view class="wrapper">
<view class="banner">
<!--头部技术支持组件-->
<commonHead></commonHead>
<image src="../../static/images/childEduBanner.jpg" mode="widthFix"></image>
</view>
<scroll-view scroll-y="true" class="formInfoContainer" id="formInfoContainer">
<view class="title"><view>小孩信息</view></view>
<view class="listContent">
<view class="ulBox">
<view class="liBox">
<view>昵称:</view>
<view><input class="uni-input" v-model="eduPlanParam.name" maxlength="10" placeholder="昵称长度不超过10" /></view>
</view>
<view class="liBox">
<view>年龄:</view>
<view><input class="uni-input" v-model="eduPlanParam.age" type="number" maxlength="2" placeholder="请输入周岁年龄" /></view>
</view>
<view class="multiline liBox">
<view class="multilineItem">
<view>是否已上学:</view>
<view class="selectBtnContent">
<text :class="{'actived':haveAcceptEduFlag}" @click="haveAcceptEduFlag=true;eduPlanParam.ngoLearn=null">是</text>
<text :class="{'actived':!haveAcceptEduFlag}" @click="haveAcceptEduFlag=false;eduPlanParam.maxGrade=null">否</text>
</view>
</view>
<view class="multilineItem" v-if="haveAcceptEduFlag">
<view>最高学历:</view>
<view>
<uni-data-picker placeholder="请选择最高学历" popup-title="请选择最高学历" :localdata="dataTree" v-model="eduPlanParam.maxGrade"
@change="onchange" @nodeclick="onnodeclick">
</uni-data-picker>
</view>
</view>
<view class="multilineItem" v-if="!haveAcceptEduFlag">
<view>几年后上学:</view>
<view><input class="uni-input" v-model="eduPlanParam.ngoLearn" type="number" maxlength="1" placeholder="请输入整数" /></view>
</view>
</view>
<view class="planGradeRange liBox">
<view>规划阶段</view>
<view>
<uni-data-picker placeholder="规划开始" popup-title="请选择规划开始阶段" :localdata="dataTree" v-model="eduPlanParam.startPlan"
@change="onchange" @nodeclick="onnodeclick">
</uni-data-picker>
<text></text>
<uni-data-picker placeholder="规划结束" popup-title="请选择规划结束阶段" :localdata="dataTree" v-model="eduPlanParam.endPlan"
@change="onchange" @nodeclick="onnodeclick">
</uni-data-picker>
</view>
</view>
</view>
</view>
<view class="title"><view>资源信息</view></view>
<view class="listContent">
<view class="ulBox">
<view class="liBox">
<view>已备教育资金总额:</view>
<view><input class="uni-input" type="digit" maxlength="15" v-model="eduPlanParam.initEducationFund" placeholder="最高保留两位小数" />万元</view>
</view>
<view class="liBox">
<view>每年预备投入教育资金总额:</view>
<view><input class="uni-input" type="digit" maxlength="15" v-model="eduPlanParam.educationDeposit" placeholder="最高保留两位小数" />万元</view>
</view>
</view>
</view>
<view class="title"><view>参数</view></view>
<view class="listContent">
<view class="ulBox">
<view class="liBox">
<view>学费增长率:</view>
<view><input class="uni-input" type="digit" maxlength="5" v-model="eduPlanParam.tuitionAddRate" placeholder="最高保留两位小数" />%</view>
</view>
<view class="liBox">
<view>资产投资回报率:</view>
<view><input class="uni-input" type="digit" maxlength="5" v-model="eduPlanParam.investmentRate" placeholder="最高保留两位小数" />%</view>
</view>
</view>
</view>
<!-- 学费设定 -->
<view class="schoolingContent">
<view class="ulBox">
<view class="liBox">
<view>学历</view>
<view>学制(年)</view>
<view style="flex-direction: column;">
<view>首年预估费用</view>
<view>(元)</view>
</view>
<view><view style="color: #ff5500;border-bottom: 1px solid #ff5500;" @click="schoolingLists=JSON.parse(JSON.stringify(dataTree))">恢复默认值</view></view>
</view>
<view class="liBox" v-for="item in schoolingLists" :key="item.value">
<view>{{item.text}}</view>
<view><input class="uni-input" maxlength="1" type="number" placeholder="最高不超过10" v-model="item.commonYears" @blur="updateSchoolingLists(item)"/></view>
<view><input class="uni-input" maxlength="10" type="digit" v-model="item.publicTuition" @blur="updateSchoolingLists(item)"/></view>
<view><view class="settingButton" @click="settingYBY(item)">逐年设定</view></view>
</view>
</view>
</view>
<!-- 测算结果及建议 -->
<view class="title"><view>测算结果及建议</view></view>
<!-- 图表 -->
<!-- 为 ECharts 准备一个定义了宽高的 DOM -->
<view id="main" style="width:96vw;height:400px" v-if="resultInfo"></view>
<view class="summaryContent" v-if="resultInfo">
<view class="successInfo" v-if="resultInfo.code=='B001'">
<strong>恭喜您!</strong>
<text>经过测算,您的资金可以负担{{eduPlanParam.name}}同学从{{getClassesInfo(getEducationNo(eduPlanParam.startPlan))}}{{getClassesInfo(getEducationNo(eduPlanParam.endPlan))}}阶段的上学费用。</text>
</view>
<view class="failInfo" v-if="resultInfo.code=='A001'">
<strong>很遗憾!</strong>
<text v-if="resultInfo.educationNo>0">经过测算,您的资金只能负担到{{eduPlanParam.name}}同学到{{getClassesInfo(resultInfo.educationNo)}}</text>
<text v-if="resultInfo.educationNo<=0">经过测算,您的资金不足以负担{{eduPlanParam.name}}同学的教育目标。</text>
</view>
<view class="suggestionInfo" v-if="resultInfo.code=='A001'">
<view>您可以这样做来实现:</view>
<view>
<view class="ulBox">
<view class="liBox">1.提高已备教育资金总额到{{Math.abs(formatFloat(resultInfo.retEducationDeposit/10000))}}万元</view>
<view class="liBox">2.提高每年预备投入教育资金总额到{{Math.abs(formatFloat(resultInfo.retInitEducationFund/10000))}}万元</view>
</view>
</view>
</view>
</view>
<!-- 操作 -->
<view class="optionContent">
<button type="default" plain="true" form-type="reset"
@click="resetData()" >全部清空</button>
<button type="default" plain="true"
class="sfp_btn" @click="educationEstimate()">开始计算</button>
</view>
</scroll-view>
</view>
<!--底部技术支持组件-->
<foot></foot>
<!-- 逐年设定弹窗 -->
<view class="dialogContainer" v-if="settingYBYFlag">
<view class="dialogContent">
<view class="closeBtn" @click="closeDialog()">×</view>
<view class="ulBox">
<view class="liBox">
<view>{{settingItem.text}}</view>
<view>预估学费</view>
</view>
<view class="liBox" v-for="(item,index) in settingItem.children">
<view>{{item.text}}</view>
<view><input class="uni-input" type="digit" placeholder="最高保留两位小数" v-model="item.tuition"/></view>
</view>
</view>
<button type="default" plain="true" @click="confirmOption()">确定</button>
</view>
</view>
</view>
</template>
<script>
import {ref} from "vue";
import commonHead from '../header/header.vue';
import foot from "../footer/footer.vue";
import {eduGradeLists} from "../../util/mock-data";
import * as echarts from 'echarts';
import api from "../../api/api";
import common from "../../common/common";
import dataHandling from "../../util/dataHandling";
import { nanoid } from "nanoid";
export default {
data() {
return {
accountBalanceEnd:[],
currentYearExpenditure:[],
xAxisLists:[],
settingItem:{},
haveAcceptEduFlag:true,
eduPlanParam:{
name:'大宝',
age:null,
ngoLearn:null,
maxGrade:null,
startPlan:null,
endPlan:null,
initEducationFund:null,
educationDeposit:null,
tuitionAddRate:2.1,
investmentRate:3.74,
incomeAddRate:0,
decimal:5
},
resultInfo:null,
settingYBYFlag:false,
isNeedOfficialAccountQrcode:true,
classes:'1-1',
dataTree: [],
schoolingLists:eduGradeLists,
flatEduGradeLists:[],
}
},
methods: {
getEducationNo(val){
if(val){
return this.flatEduGradeLists.filter(item=>item.value==val)[0].educationNo;
}else{
return null;
}
},
getClassesInfo(val){
if(val){
const value = this.flatEduGradeLists.filter(item=>item.educationNo==val)[0].value;
if(value){
const schooling = value.split('-')[0];
const grade = value.split('-')[1];
let schoolingName = '';
switch(schooling){
case '1':
schoolingName = '幼儿园';
break;
case '2':
schoolingName = '小学';
break;
case '3':
schoolingName = '初中';
break;
case '4':
schoolingName = '高中';
break;
case '5':
schoolingName = '大学';
break;
case '6':
schoolingName = '硕士';
break;
case '7':
schoolingName = '博士';
break;
default:
schoolingName = '幼儿园';
break;
}
return (schoolingName + grade + '年级');
}else{
return val;
}
}
},
getFollowData(e){
this.isNeedOfficialAccountQrcode= ref(e);
},
onnodeclick(e) {
console.log(e);
},
onchange(e) {
// console.log('onchange:', e);
},
drawLine(){
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
title: {},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
legend: {
data: ['教育金账户', '学费现金流'],
left:'1%'
},
grid: {
left: '2%',
containLabel: true
},
xAxis: [
{
type: 'category',
boundaryGap: false,
axisLabel:{
interval:0,
rotate:60
},
textStyle:{
fontSize:10
},
data: this.xAxisLists
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: '教育金账户',
type: 'line',
itemStyle:{
color:'#2E9200'
},
lineStyle:{
color:'#46B700'
},
areaStyle: {
color:'#A5D58F'
},
emphasis: {
focus: 'series'
},
data:this.accountBalanceEnd,
},
{
name: '学费现金流',
type: 'line',
stack: 'Total',
itemStyle:{
color:'#C58906'
},
lineStyle:{
color:'#E39C00'
},
areaStyle: {
color:'#FFAF00'
},
emphasis: {
focus: 'series'
},
data:this.currentYearExpenditure,
}
]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
},
settingYBY(item){
// 逐年设定
this.settingYBYFlag = true;
this.settingItem = item;
},
updateSchoolingLists(val){
if(Number(val.commonYears) != val.children.length){
if(Number(val.commonYears) > 0){
const arr = [];
for(let i=0;i< Number(val.commonYears);i++){
arr.push({text:`${i+1}年级`,value:`${val.value}-${i+1}`,tuition:null})
}
val.children = arr;
}
}
if(val.publicTuition){
val.children[0].tuition = val.publicTuition;
}
},
closeDialog(){
this.settingYBYFlag = false;
},
confirmOption(){
this.settingYBYFlag = false;
this.schoolingLists.filter(item=>item.value==this.settingItem.value)[0].publicTuition = this.settingItem.children[0].tuition;
},
objFlat(Data){
// 对象数组拍平
const flatData = (data, parentId = undefined) => {
return data.reduce((prev, curr) => {
if (parentId != undefined) {
Object.assign(curr, {
parentId: parentId,
});
}
if(parentId){
prev.push(curr);
}
if (curr.children && curr.children.length > 0) {
prev.push(...flatData(curr.children,curr.value));
}
return prev;
}, []);
};
let flated = flatData(Data);
return flated;
},
educationEstimate(){
this.flatEduGradeLists = JSON.parse(JSON.stringify(this.objFlat(this.schoolingLists)))
this.flatEduGradeLists.map((val,idx)=>{
val['educationNo'] = idx + 1;
});
// 数据校验
if(this.eduPlanParam.age && (this.eduPlanParam.age > 40 || this.eduPlanParam.age < 0) ){
common.errorDialog(2,'子女教育规划一般年龄不会小于0且不超过40岁');
return false;
}else if(this.haveAcceptEduFlag && !this.eduPlanParam.maxGrade){
common.errorDialog(1,'为了精准测算,请选择小孩的最高学历');
return false;
}else if(!this.haveAcceptEduFlag && !this.eduPlanParam.ngoLearn && this.eduPlanParam.ngoLearn!=0){
common.errorDialog(1,'为了精准测算,请填写小孩几年后上学');
return false;
}else if(!this.eduPlanParam.startPlan || !this.eduPlanParam.endPlan){
common.errorDialog(1,'为了精准测算,请选择规划阶段');
return false;
}else if(this.getEducationNo(this.eduPlanParam.startPlan) >= this.getEducationNo(this.eduPlanParam.endPlan)){
common.errorDialog(1,'您的规划起始阶段应小于结束阶段');
return false;
}else if(this.haveAcceptEduFlag && this.eduPlanParam.maxGrade > this.eduPlanParam.startPlan){
common.errorDialog(2,'规划开始阶段应大于或等于最高学历');
return false;
}else if((!this.eduPlanParam.initEducationFund && this.eduPlanParam.initEducationFund!=0) || this.eduPlanParam.initEducationFund < 0){
common.errorDialog(1,'请输入目前您已备教育资金总额');
return false;
}else if(!this.eduPlanParam.educationDeposit && this.eduPlanParam.educationDeposit!=0){
common.errorDialog(1,'请输入您每年预备投入教育资金总额');
return false;
}
const flatSchoolingLists = JSON.parse(JSON.stringify(this.objFlat(this.schoolingLists)));
for(let i=0;i<flatSchoolingLists.length;i++){
flatSchoolingLists[i]['educationNo']=i+1;
flatSchoolingLists[i]['educationGrade']=flatSchoolingLists[i].value ? flatSchoolingLists[i].value.split('-')[0] : null;
flatSchoolingLists[i]['gradeNo']=flatSchoolingLists[i].value ? flatSchoolingLists[i].value.split('-')[1] : null;
flatSchoolingLists[i]['tuition']=flatSchoolingLists[i].tuition ? flatSchoolingLists[i].tuition : null;
flatSchoolingLists[i]['text']=flatSchoolingLists[i]['parentId']=flatSchoolingLists[i]['value']=undefined;
}
const param = {
...this.eduPlanParam,
businessNo:nanoid(),
wechat_openid:uni.getStorageSync('openId') || '',
tuitionAddRate:(this.eduPlanParam.tuitionAddRate/100).toFixed(4),
investmentRate:(this.eduPlanParam.investmentRate/100).toFixed(4),
maxGrade:this.getEducationNo(this.eduPlanParam.maxGrade),
startPlan:this.getEducationNo(this.eduPlanParam.startPlan),
endPlan:this.getEducationNo(this.eduPlanParam.endPlan),
educationTuitionInfos:flatSchoolingLists,
initEducationFund:this.eduPlanParam.initEducationFund * Math.pow(10,4),
educationDeposit:this.eduPlanParam.educationDeposit * Math.pow(10,4),
userId:uni.getStorageSync('cffp_userId'),
systemType:1
}
api.educationEstimate(param).then(res=>{
this.resultInfo = res['data'];
if(res['success']){
this.currentYearExpenditure = [];
this.accountBalanceEnd = [];
this.xAxisLists = [];
const result = this.resultInfo.educationEstimateResInfos;
for(let i=0;i<result.length;i++){
this.currentYearExpenditure.push(Math.abs(result[i]['currentYearExpenditure']));
this.accountBalanceEnd.push(result[i]['accountBalanceEnd']);
this.xAxisLists.push(result[i]['educationNo'] ? this.getClassesInfo(result[i]['educationNo']) : result[i]['planyear'])
}
setTimeout(()=>{this.drawLine()},0)
}else{
this.currentYearExpenditure = [];
this.accountBalanceEnd = [];
this.xAxisLists = [];
common.errorDialog(2,res['message']);
return false;
}
})
},
resetData(){
this.eduPlanParam = {
name:'',
age:null,
ngoLearn:null,
maxGrade:null,
startPlan:null,
endPlan:null,
initEducationFund:null,
educationDeposit:null,
tuitionAddRate:2.1,
investmentRate:3.74,
incomeAddRate:0,
decimal:5
}
this.schoolingLists.map(item=>{
item.publicTuition=null;
item.children.map(val=>val.tuition=null)
})
},
/*
num:源数据
digitNum:保留几位小数
type:向上(1)取还是向下(2)取
*/
formatFloat(num,digitNum=2,type=1){
return common.formatFloat(num,digitNum=2,type=1)
}
},
mounted() {
this.dataTree = JSON.parse(JSON.stringify(eduGradeLists));
this.flatEduGradeLists = JSON.parse(JSON.stringify(this.objFlat(this.schoolingLists)))
this.flatEduGradeLists.map((val,idx)=>{
val['educationNo'] = idx + 1;
});
},
components:{
commonHead,
foot
}
}
</script>
<style>
@import '../sfpCommon.css';
@import url("childEdu.css");
</style>
/* 保单年度弹窗 */
.policySelectContainer{
position: fixed;
z-index: 2;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.35);
}
.policySelectContainer .policyYearContainer{
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 57%;
background-color: #fff;
border-top-left-radius: 40rpx;
border-top-right-radius: 40rpx;
padding: 20rpx 30rpx 0;
box-sizing: border-box;
overflow-y: scroll;
}
.policyYearContainer .modalTitle{
display: flex;
justify-content: space-between;
align-items: center;
font-weight: bold;
}
.policyYearContainer .modalTitle text:last-child{
color: #FF0000;
}
.policyYearItemContainer{
display: flex;
flex-wrap: wrap;
justify-content: space-around;
}
.policyYearItemContainer view{
width: 9%;
height: 0;
padding-bottom: 9%;
margin: 20rpx 0;
color: #fff;
border-radius: 50%;
position: relative;
margin-right: 6rpx;
color: #333;
font-weight: bold;
}
.policyYearItemContainer view.actived{
background: linear-gradient(135deg, #CEB07D 0%, #FFDDA9 56%, #FED495 100%, #FED495 100%);
color:#6B4000;
}
.policyYearItemContainer view text{
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-55%);
}
.policyStepContainer{
display: flex;
justify-content: space-around;
margin-top: 40rpx;
}
.policyStepContainer button{
flex: 0 0 30%;
font-size: 32rpx;
color:#000;
font-weight:bold;
border:1px solid #CEB07D;
}
.policyStepContainer uni-button::after{
border:1px solid #CEB07D;
}
.policyStepContainer button.actived{
background: linear-gradient(135deg, #CEB07D 0%, #FFDDA9 56%, #FED495 100%, #FED495 100%);
color: #6B4000;
}
.policyStepContainer button.actived,.policyStepContainer button.actived::after{
border:none;
}
.confirm button{
background: linear-gradient(135deg, #CEB07D 0%, #FFDDA9 56%, #FED495 100%, #FED495 100%);
color: #6B4000;
font-weight: bold;
font-size: 36rpx;
margin-top: 56rpx;
width: 300rpx;
}
.confirm button,.confirm button::after{
border: none ;
}
.uni-textarea{
position: relative;
}
.pasteDiscernment{
position: absolute;
right: 0;
bottom: 0;
height: 50rpx;
background: #9B8055;
border-radius: 100px;
color: #fff;
font-size: 24rpx;
}
.batchDataImportContainer{
background-color: #fbfbfb;
height: 90vh;
}
.batchDataLists{
margin-top: 20rpx;
background: #fff;
}
.batchDataLists view{
display: flex;
justify-content: center;
align-items: center;
}
.batchDataLists view text:first-child{
display: inline-block;
width: 100%;
flex: auto;
text-align: center;
border-right: 1px solid #e4e4e4;
}
.batchDataLists view.batchDataTh{
background:linear-gradient(135deg, #CEB07D 0%, #FFDDA9 56%, #FED495 100%, #FED495 100%);
border-top-left-radius: 12rpx;
border-top-right-radius: 12rpx;
min-height: 80rpx;
}
.batchDataTh .pvTitle{
display: flex;
flex-direction: column;
flex: 0 0 65%;
justify-content: center;
align-items: center;
}
.batchDataTh > view:first-child,.batchDataTd > view:first-child{
width: 0;
flex: 0 0 35%;
justify-content: center;
}
.batchDataTh > view:last-child,.batchDataTd > view:last-child{
width: 0;
flex: 0 0 65%;
justify-content: center;
}
.batchDataTh .pvTitle view{
border: none;
}
.batchDataLists view.batchDataTd{
display: flex;
height: 80rpx;
line-height: 80rpx;
border-bottom: 1px solid #e4e4e4;
}
.dataOptionContainer{
margin: 20rpx 20rpx 0;
margin-bottom: 34rpx;
}
.dataOptionContainer .uni-textarea{
background-color: #fff;
margin-bottom: 20rpx;
}
.tips{
font-size: 24rpx;
color: #666;
padding: 0 20rpx 20rpx;
background-color: #fff;
}
.tips text text{
font-size: 28rpx;
color: #9B8055;
font-weight: bold;
}
.selectStepContent,.selectStepContainer{
display: flex;
align-items: center;
}
.selectStepContainer{
justify-content: space-between;
padding: 20rpx 20rpx 0;
background-color: #fff;
}
.stepContent{
display: flex;
align-items: center;
border-bottom: 1px solid #e4e4e4;
padding: 0 5px;
}
.selectStepContainer button{
background-color: transparent;
}
.selectStepContainer button::after{
border: 1px solid #CEB07D;
}
.optionContent{
position: fixed;
bottom: 0;
left: 0;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
background-color: #fff;
}
.optionContent button{
flex: 0 0 46%;
border:2rpx solid #e7c793;
color: #6B4000;
font-size: 36rpx;
}
.optionContent button:last-child{
background: linear-gradient(135deg, #CEB07D 0%, #FFDDA9 56%, #FED495 100%, #FED495 100%);
border: none;
}
.batchDataTd input{
height: 100%;
}
\ No newline at end of file
<template>
<view class="batchDataImportContainer">
<view class="selectStepContainer">
<view class="selectStepContent">
<text>我想测算每隔</text>
<view class="stepContent">
<picker @change="bindPickerChange" :value="index" :range="stepLists">
<view class="uni-input">{{stepLists[index]}}</view>
</picker>
<svg t="1661847421137" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1364" width="16" height="16"><path d="M917.4 302.8c-14.2-14.2-37.2-14.2-51.4 0L518.6 650.3c-2.9 2.8-7.5 2.8-10.3 0L160.8 302.8c-14.2-14.2-37.2-14.2-51.4 0-14.2 14.2-14.2 37.2 0 51.4l347.4 347.4c15.6 15.6 36 23.4 56.5 23.4s41-7.8 56.5-23.4l347.4-347.4c14.3-14.2 14.3-37.2 0.2-51.4z" p-id="1365" fill="#666666"></path></svg>
</view>
<text>年的单利复利</text>
</view>
<!-- 自定义 -->
<view>
<button class="mini-btn" type="default" size="mini" @click="selectCustomPolicyYear">自定义</button>
</view>
</view>
<!-- 提示信息-->
<view class="tips">
<text>(如需指定任意保单年度,可通过点击右上角<text>“自定义”</text>按钮完成)</text>
</view>
<view class="dataOptionContainer">
<!-- 粘贴数据区域 -->
<view class="uni-textarea">
<textarea v-model="pasteData" placeholder-style="color:#999999;font-size:14px;padding-left:9px;padding-top:3px" placeholder="请根据左侧保单年度进行现金价值数据粘贴,如您想直接输入数据,需使用回车键或换行符分隔"/>
<button class="mini-btn pasteDiscernment" type="default" size="mini" @click="pasteDataDistinguish">粘贴并识别</button>
</view>
<!-- 批量数据输入区域 -->
<view class="batchDataLists">
<view class="batchDataTh" v-if="!pvFlag">
<view>保单年度</view>
<view>现金价值</view>
</view>
<view class="batchDataTh" v-if="pvFlag">
<view>保单年度</view>
<view class="pvTitle">
<view>总生存利益</view>
<view style="font-size: 24rpx;margin-top: 4rpx;">(现金价值+万能账户)</view>
</view>
</view>
<scroll-view scroll-y="true" style="height: 560rpx;">
<view class="batchDataTd" v-for="item in irrAndSimpleInfos">
<view>
<text>{{item.nyear}}</text>
</view>
<view>
<input class="uni-input" style="height: 100%;" type="digit" v-model="item.cashValue" placeholder="输入数字,如100" maxlength="17"/>
</view>
</view>
</scroll-view>
</view>
</view>
<!-- 操作 -->
<view class="optionContent">
<button type="default" plain="true" form-type="reset" @click="clearData">全部清空</button>
<button type="default" plain="true" @click="calcuteIrr()">{{calcuteMethod=='2' ? '输入批量数据' : '开始计算'}}</button>
</view>
<!-- 保单年度选择弹窗 -->
<view class="policySelectContainer" v-if="policyYearModalFlag">
<view class="policyYearContainer">
<view class="modalTitle">
<text></text>
<text>选择保单年度<text>(可多选)</text></text>
<icon :type="'clear'" size="26" @click="policyYearModalFlag=false"/>
</view>
<view class="policyStepContainer">
<button type="default" plain="true" :class="{'actived': customPolicyYearRange===0 }" @click="selectPolicyYearRange(0)">1~40</button>
<button type="default" plain="true" :class="{'actived': customPolicyYearRange===1 }" @click="selectPolicyYearRange(1)">41~80</button>
<button type="default" plain="true" :class="{'actived': customPolicyYearRange===2 }" @click="selectPolicyYearRange(2)">81~105</button>
</view>
<view class="policyYearItemContainer">
<view v-for="item of customPolicyYearRangeCount" @click="selectCustomPolicyYears(item + customPolicyYearRange * customPolicyYearRangeCount)" :class="{'actived':getActiveStatus(item + customPolicyYearRange * customPolicyYearRangeCount)}">
<text>{{item + customPolicyYearRange * customPolicyYearRangeCount > this.maxPolicyYear ? '' : item + customPolicyYearRange * customPolicyYearRangeCount}}</text>
</view>
</view>
<view class="confirm">
<button type="default" plain="true" @click="confirmPolicyYears()">确定</button>
</view>
</view>
</view>
</view>
</template>
<script>
import api from "../../api/api";
import {reactive,provide} from "vue";
export default {
data() {
return {
index:0,
stepLists:[1,5,10,15,20],
pasteData:"",
irrAndSimpleInfos:[{nyear:1,cashValue:''}],
customPolicyYearRange:0,
customPolicyYearRangeCount:40,
maxPolicyYear:105,
policyYearLists:[{nyear:1,isActived:true,cashValue:''}],
policyYearModalFlag:false,
calcuteData:null,
pvFlag:false
}
},
name:'dataImport',
onLoad(option) {
this.pvFlag = option.isUniversalAccount=='1' ? true : false;
this.bindPickerChange({detail:{value:this.index}});
this.calcuteData = uni.getStorageSync('calcuteData') ? JSON.parse(uni.getStorageSync('calcuteData')) : null;
},
methods:{
// 选择间隔
bindPickerChange(e){
this.index = e.detail.value;
const m = this.stepLists[this.index]===1 ? 2 : 1;
this.policyYearLists = [{nyear:1,isActived:true,cashValue:''}];
for(let n=m;n<=this.maxPolicyYear;n++){
let calcNumber = this.stepLists[this.index] * n;
if(calcNumber <= this.maxPolicyYear){
this.policyYearLists = this.policyYearLists.concat([{nyear:calcNumber,cashValue:''}]) ;
}else{
break;
}
}
this.irrAndSimpleInfos = this.policyYearLists.concat([]);
},
// 选择自定义
selectCustomPolicyYear(){
this.policyYearModalFlag=true;
this.irrAndSimpleInfos = this.policyYearLists = [];
},
// 选择保单年度区间
selectPolicyYearRange(e){
this.customPolicyYearRange = e;
},
// 选择保单年度(自定义)
selectCustomPolicyYears(e){
if(this.policyYearLists.filter(item=>item.nyear==e).pop()){
this.policyYearLists.filter(item=>item.nyear==e).pop()['isActived'] = !this.policyYearLists.filter(item=>item.nyear==e).pop()['isActived']
}else{
this.policyYearLists.push({nyear:e,isActived:true,cashValue:''})
}
},
// 获取选中状态
getActiveStatus(e){
let status = false;
if(this.policyYearLists.filter(item=>item.nyear==e).pop()){
status = this.policyYearLists.filter(item=>item.nyear==e).pop()['isActived']
}
return status;
},
// 确认选择的保单年度
confirmPolicyYears(){
this.policyYearModalFlag = false;
if(this.policyYearLists.length>0){
this.policyYearLists.sort((a,b)=>a.nyear - b.nyear)
}
this.irrAndSimpleInfos = JSON.parse(JSON.stringify(this.policyYearLists));
},
// 粘贴并识别
pasteDataDistinguish(){
let pasteDataListsOrigin = this.pasteData.trim().split('\n');
let pasteDataLists;
pasteDataLists = pasteDataListsOrigin.map(item=>item.trim());
if(pasteDataLists.length<=0 || pasteDataLists.every((item)=>item=='')){
uni.showModal({
title: '数据识别结果',
content: '检测到您并没有导入数据,请重新操作',
success: function (res) {
if (res.confirm) {
console.log('用户点击确定');
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
}else if(pasteDataLists.length !== this.irrAndSimpleInfos.length){
uni.showModal({
title: '数据识别结果',
content: '检测到您导入的数据条数和选择的保单年度数量不一致,系统将从上到下依次填入,请确认是否继续',
success: (res)=> {
if (res.confirm) {
console.log('用户点击确定');
if(this.irrAndSimpleInfos.length>0){
const minLength = Math.min(pasteDataLists.length,this.irrAndSimpleInfos.length) ;
for(let i=0;i<minLength;i++){
this.irrAndSimpleInfos[i]['cashValue'] = pasteDataLists[i];
}
}
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
}else{
if(this.irrAndSimpleInfos.length>0){
const minLength = Math.min(pasteDataLists.length,this.irrAndSimpleInfos.length) ;
for(let i=0;i<minLength;i++){
this.irrAndSimpleInfos[i]['cashValue'] = pasteDataLists[i];
}
}
}
},
// 全部清空
clearData(){
this.pasteData = '';
this.irrAndSimpleInfos.forEach(item=>item.cashValue='');
},
// 开始计算
calcuteIrr(){
this.policyYearLists = this.irrAndSimpleInfos.filter(item=>item.cashValue!=='')
if(this.policyYearLists.length<=0){
uni.showModal({
title: '必填提醒',
content:`系统检测到您并未录入有效的现金价值数据!`,
showCancel:false,
success: function (res) {
if (res.confirm) {
console.log('用户点击确定');
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
return;
}
console.log(this.policyYearLists)
for(let i=0;i<this.policyYearLists.length;i++){
if(this.policyYearLists[i].cashValue<0 || isNaN(this.policyYearLists[i].cashValue || this.policyYearLists[i].cashValue > 999999999999999)){
uni.showModal({
title: '数据格式输入错误',
content: `保单年度为${this.policyYearLists[i].nyear}时,现金价值格式错误,须为大于或等于0且必须小于999,999,999,999,999的数字类型`,
showCancel:false,
success: function (res) {
if (res.confirm) {
console.log('用户点击确定');
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
return;
}
}
const params = reactive({
...this.calcuteData,
calcuteMethod:2,
decimal:5,
irrAndSimpleInfos:this.policyYearLists
});
// provide("dataImportIrrAndSimpleCalcuteParams", params);
// uni.navigateTo({
// url: '/pages/index/index'
// });
api.irrAndSimpleCalcute(params).then(res=>{
if(res.success === true){
this.irrAndSimpleResInfos = res.data.irrAndSimpleResInfos;
// this.resultShowFlag = true;
//计算成功返回上一页
uni.setStorageSync('resIrrAndSimpleResInfos',this.irrAndSimpleResInfos);
// uni.navigateBack({
// delta:1,//返回层数,2则上上页
// })
uni.navigateTo({
url: '/sfp/index/index?isBack=1'
});
}else{
uni.showToast({
title: res['message'],
duration: 2000,
icon: 'none'
})
}
})
}
}
}
</script>
<style>
@import 'data-import.css'
</style>
\ No newline at end of file
<template>
<view class="supportDeclarationContainer">
<img src="/static/images/cffpLogo.png" alt="" srcset="">
<text>本工具由CFFP财策师联盟提供技术支持</text>
</view>
</template>
<script>
export default{
data(){
return{}
},
name:'foot',
components:{
},
onLoad(){
},
methods:{
}
}
</script>
<style>
.supportDeclarationContainer{
padding-bottom: 160rpx;
text-align: center;
color: #ccc;
display: flex;
justify-content: center;
align-items: center;
}
.supportDeclarationContainer img{
width: 60rpx;
}
</style>
\ No newline at end of file
<template>
<view class="supportTips">
<img src="/static/images/cffpLogo.png" alt="" srcset="">
<text>本工具由CFFP财策师联盟提供技术支持</text>
</view>
</template>
<script>
export default{
data(){
return{}
},
name:'commonHead',
components:{
},
onLoad(){
},
methods:{
}
}
</script>
<style>
.supportTips{
position: absolute;
top: 0;
right: 0;
display: flex;
justify-content: center;
align-items: center;
font-size: 26rpx;
width: 100%;
padding: 0rpx 12rpx;
background: rgba(255,255,255,.5);
color: #000;
z-index: 1;
}
.supportTips text{
white-space: nowrap;
}
.supportTips img{
width: 60rpx;
}
</style>
\ No newline at end of file
<template>
<view class="wrapper">
<view class="banner">
<!--头部技术支持组件-->
<commonHead></commonHead>
<image src="../../static/images/banner.png" mode="widthFix"></image>
</view>
<scroll-view scroll-y="true" class="formInfoContainer" id="formInfoContainer">
<form>
<!--需求信息-->
<view class="demandInfo">
<view class="title">
<view>
需求信息
</view>
</view>
<view class="inputItem">
<text>几年后购房:</text>
<view class="inputContent">
<input class="uni-input" type="number" placeholder="请输入"
maxlength="3" v-model="housePurchaseInfo.nyear" />
<label for=""></label>
</view>
</view>
<view class="inputItem">
<text>预购城市:</text>
<uni-data-picker placeholder="请选择地区" popup-title="请选择所在地区" :localdata="provinceList"
@change="onchange" @nodeclick="onnodeclick" v-model="housePurchaseInfo.cityId">
</uni-data-picker>
</view>
<view class="inputItem">
<text>预购面积:</text>
<view class="inputContent">
<input class="uni-input" type="digit" placeholder="请输入" maxlength="6"
v-model="housePurchaseInfo.preOrderSize" @blur="queryCommercialHousingPrice()"
/><label for=""></label>
</view>
</view>
<view class="inputItem">
<text>预购房产现在市场单价:</text>
<view class="inputContent">
<input class="uni-input" type="digit" placeholder="请输入"
v-model="housePurchaseInfo.targetPrice" maxlength="12"
/><label for="">元/m²</label>
</view>
</view>
<view class="inputItem">
<text>首付款最低成数:</text>
<view class="inputContent">
<input class="uni-input" type="number" placeholder="请输入"
maxlength="3" v-model="housePurchaseInfo.downPaymentMin"
/><label for="">%</label>
</view>
</view>
<view class="inputItem">
<text>新房贷款年限:</text>
<view class="inputContent">
<input class="uni-input" type="number" placeholder="请输入"
maxlength="3" v-model="housePurchaseInfo.newLoanYear"
/><label for=""></label>
</view>
</view>
<view class="inputItem">
<text>新房贷款年利率:</text>
<view class="inputContent">
<input class="uni-input" type="digit" placeholder="请输入"
maxlength="4" v-model="housePurchaseInfo.interestRate"
/><label for="">%</label>
</view>
</view>
<view class="inputItem">
<text style="flex: 0 0 30%;">购房用途:</text>
<view class="btn_wrapper">
<view class="btn_item"
:class="{ 'selected': housePurchaseInfo.housePurchaseType==housePurchaseTypeItem.id }"
v-for="housePurchaseTypeItem in housePurchaseTypeList"
@click="housePurchase(housePurchaseTypeItem.id)">
{{housePurchaseTypeItem.name}}
</view>
</view>
</view>
</view>
<!--资源信息-->
<view class="sourcesInfo">
<view class="title">
<view>
资源信息
</view>
</view>
<view class="inputItem">
<text>已备首付:</text>
<view class="inputContent">
<input class="uni-input" type="digit" placeholder="请输入"
v-model.trim="housePurchaseInfo.firstHouseAmount" maxlength="8"
/><label for="">万元</label>
</view>
</view>
<view class="inputItem" style="position: relative;">
<view>
<view>每年投入房产资金:</view>
<view style="position: absolute;left: 0;bottom: -1px;font-size: 24rpx;color: red;letter-spacing: 1px;">(从今年末开始投入,用于首付和按揭)</view>
</view>
<view class="inputContent">
<input class="uni-input" type="digit" placeholder="请输入"
v-model="housePurchaseInfo.repaymentSpecial" maxlength="8"
/><label for="">万元/年</label>
</view>
</view>
</view>
<!--房屋置换-->
<view class="houseInfo">
<!-- <view class="title">
<view style="display: flex;">
<view class="radioButton" :class="{'selected':isDisplace }"
@click="openLoan()"></view>
<text style="margin-left: 10rpx;">是否置换旧房</text>
</view>
<view class="editParam" v-if="dataLists" @click="editParams()">修改参数</view>
</view> -->
<view v-if="dataLists">
<loanBalance :isReadonly="true" :a="accumulationFundParams" :b="commercialLoansParams" @getData="getData"></loanBalance>
</view>
</view>
<!--规划参数-->
<view class="parametersInfo">
<view class="title">
<view>
规划参数
</view>
<view class="view" @click="viewPlanningParams()">
查看
</view>
</view>
</view>
<!-- 操作 -->
<view class="optionContent">
<button type="default" plain="true" form-type="reset"
@click="resetData()" >全部清空</button>
<button type="default" plain="true"
class="sfp_btn" @click="startCount()">开始计算</button>
</view>
</form>
<!--测算结果-- v-show="resultFlag"-->
<view class="result_wrapper" v-if="resultFlag">
<view class="suggestInfo">
<view class="title">
<view>
测算结果及建议
</view>
</view>
<view class="chartsLegend">
<radio-group @change="radioChange" style="display: flex;width: 100%;justify-content: space-evenly;">
<label v-for="(item, index) in chartsLegends" :key="item.value" style="display: flex;">
<view style="display: flex;">
<radio :value="item.value" :checked="item.value === chartsLegendsCurrent" />
</view>
<view style="font-size: 28rpx;">{{item.name}}</view>
</label>
</radio-group>
</view>
<view id="myEcharts" style="height: 450rpx;"></view>
<view style="text-align: center;color: #c3c1c1;font-size: 22rpx;" v-if="isNeedDis">
差额 = 可实现的 - 你想要的
</view>
<view class="resultSummaryContent">
<view v-if="resultInfos.code == 'B001' || resultInfos.code =='B002'" style="display: flex;align-items: center;">
<view style="margin-right: 8rpx;">
<img src="../../static/images/happy.png" alt="" srcset="">
</view>
<view>
<view>恭喜您!</view>
<view>您实现买房自由了哦~</view>
</view>
</view>
<view v-if="resultInfos.code == 'A001' || resultInfos.code =='A002'" style="display: flex;align-items: center;">
<view style="margin-right: 8rpx;">
<img src="../../static/images/sad.png" alt="" srcset="">
</view>
<view>
<view>很遗憾!</view>
<view>您还不能实现目标,请继续加油哦~</view>
</view>
</view>
</view>
<view style="background: rgba(36,255,0,3%);padding: 6rpx 10rpx;border-radius: 12rpx;line-height: 1.5;">
<view v-if="resultInfos.code == 'A001' || resultInfos.code =='A002'" style="display: flex;">
<text class="seriesNo">1</text>
<view>如您想实现<strong>{{resultInfos.nyear}}</strong>年后在<strong>{{resultInfos.provinceName}}-{{resultInfos.cityName}}</strong>地区购买
<strong>{{resultInfos.preOrderSize}}</strong>㎡的房产,那么您还需要提高首付款到
<strong>{{formatFloat(resultInfos.pvDownPayment/10000,2,1)}}</strong>万元,或您需提高每年投入房产资金到
<strong>{{formatFloat(resultInfos.houseSpecialPurpose/10000)}}</strong>万元。 </view>
</view>
<view style="margin-top: 10rpx;display: flex;">
<text class="seriesNo">{{resultInfos.code == 'A001' || resultInfos.code =='A002'?'2':'1'}}</text>
<view>根据您的已备首付款和每年投入房产资金测算,您在<strong>{{resultInfos.nyear}}</strong>年后最高可实现购买房屋单价为<strong>{{formatFloat(tipsPrice/10000)}}</strong>万元/㎡,总价为<strong>{{formatFloat(tipsTotalPrice/10000)}}</strong>万元的房产。</view>
</view>
</view>
</view>
<view class="line" v-for="houseItem in housePurchasePrices">
<view class="line_title">{{getResultTitle(houseItem.priceType)}}
<img src="../../static/images/can.png" alt="" v-show="houseItem.fvDifference <= 0">
<img src="../../static/images/cannot.png" alt="" v-show="houseItem.fvDifference > 0">
</view>
<view class="content">
<view class="left">
<view class="realizable">可实现的</view>
<view>{{housePurchaseInfo.nyear}}年后:{{formatFloat(houseItem.fvPriceRealization/10000)}}万元</view>
<!-- <view class="now">
现值:{{numberConverter(houseItem.pvPriceRealization)}}
</view> -->
</view>
<img src="../../static/images/vs.png" alt="">
<view class="right">
<view class="realizable">你想要的</view>
<view>{{housePurchaseInfo.nyear}}年后:{{formatFloat(houseItem.fvPriceDesired/10000)}}万元</view>
<!-- <view class="now">
现值:{{numberConverter(houseItem.pvPriceDesired)}}
</view> -->
</view>
</view>
<view class="line_bottom" v-show="houseItem.fvDifference <= 0">
<strong style="font-size: 36rpx;">恭喜您!</strong>
<text>经过测算,</text>
<text v-if="houseItem.fvDifference < 0">您的{{getResultTitle(houseItem.priceType)}}已超出目标值{{Math.abs(formatFloat(houseItem.fvPriceRealization/10000)-formatFloat((houseItem.fvPriceDesired/10000))).toFixed(2)}}万元,</text>
<text v-if="houseItem.fvDifference == 0">您的{{getResultTitle(houseItem.priceType)}}</text>
<text>{{resultInfos.nyear}}年后{{getResultTitle(houseItem.priceType)}}可以满足您的需求.</text>
</view>
<view class="line_bottom fail" v-show="houseItem.fvDifference > 0">
<strong style="font-size: 36rpx;">很遗憾!</strong>
经过测算,距离实现您的{{getResultTitle(houseItem.priceType)}}目标还差{{Math.abs(formatFloat(houseItem.fvDifference/10000))}}万元。您可以参考我们给出的建议进行调整。
</view>
</view>
</view>
</scroll-view>
<!--底部技术支持组件-->
<foot></foot>
</view>
<view class="mask" v-if="dialogIsShow">
<view class="content">
<!-- 关闭按钮 -->
<view class="closeBtn" @click="closeBtn()">
<svg t="1663922894848" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2545" width="26" height="26"><path d="M557.311759 513.248864l265.280473-263.904314c12.54369-12.480043 12.607338-32.704421 0.127295-45.248112-12.512727-12.576374-32.704421-12.607338-45.248112-0.127295L512.127295 467.904421 249.088241 204.063755c-12.447359-12.480043-32.704421-12.54369-45.248112-0.063647-12.512727 12.480043-12.54369 32.735385-0.063647 45.280796l262.975407 263.775299-265.151458 263.744335c-12.54369 12.480043-12.607338 32.704421-0.127295 45.248112 6.239161 6.271845 14.463432 9.440452 22.687703 9.440452 8.160624 0 16.319527-3.103239 22.560409-9.311437l265.216826-263.807983 265.440452 266.240344c6.239161 6.271845 14.432469 9.407768 22.65674 9.407768 8.191587 0 16.352211-3.135923 22.591372-9.34412 12.512727-12.480043 12.54369-32.704421 0.063647-45.248112L557.311759 513.248864z" p-id="2546"></path></svg>
</view>
<!--旧房贷款余额组件-->
<loanBalance v-if="isLoanSelected" :a="accumulationFundParams" :b="commercialLoansParams" :loanType="1" @getData="getData"></loanBalance>
<!--规划参数组件-->
<planningParameters v-if="paramsSelected" :cityInfo="cityInfo" :planningParams="planningParams" @getData="getPlanParams"></planningParameters>
</view>
</view>
</template>
<script>
import {toRefs,ref} from "vue";
import loanBalance from './loanBalance.vue';
import planningParameters from './planningParameters.vue';
import commonHead from '../header/header.vue';
import foot from '../footer/footer.vue';
import * as echarts from 'echarts';
import api from '../../api/api';
import common from '../../common/common';
import dataHandling from "../../util/dataHandling";
import { nanoid } from "nanoid";
export default{
data(){
return{
chartsLegendsCurrent: '1',
chartsLegends:[{
value: '1',
name: '总房款(万元)',
checked: 'true'
},
{
value: '3',
name: '首付款(万元)'
},{
value: '4',
name: '总贷款(万元)'
}],
isNeedDis:true,
isNeedOfficialAccountQrcode:true,
tipsPrice:null,
tipsTotalPrice:null,
cityInfo:{},
isEditFlag:false,
dataLists:null,
dialogIsShow:false,//弹窗显示与隐藏
isDisplace:false,
isLoanSelected:false,
paramsSelected:false,
myChart:null,
provinceList: [],
housePurchaseInfo:{
nyear:null,//几年后购房
provinceCode:null,
provinceName:null,
cityCode:null,
cityName:null,
preOrderSize:null,//预购面积
targetPrice:null,//目标价格(现值)
downPaymentMin:30,//首付款最低成数(百分位)
newLoanYear:null,//新房贷款年限【必须大于0】
firstHouseAmount:null,//初期购房资金(单位万)
housePurchaseType:2,//购房用途
repaymentSpecial:null,//每年还贷专用款(单位万)
interestRate:null, //贷款年利率
},
housePurchaseTypeList:[{id:1,name:'投资'},{id:2,name:'自住'},{id:3,name:'其他'}],
houseLoanOldList:[],
accumulationFundParams:[],
commercialLoansParams:[],
downPaymentList:[],
totalLoanList:[],
totalPriceList:[],
resultInfos:{
nyear:null, //几年后购房
preOrderSize:null, //预购面积
provinceName:null, //预购省名称
cityName:null, //预购城市名称
pvDownPayment:null, //提高已备首付款到
houseSpecialPurpose:null, //提高每年还贷专用款到
},
housePurchasePrices:[],
resultFlag:false,
planningParams:{}
}
},
components:{
loanBalance,
planningParameters,
foot,
commonHead,
},
onLoad(){
this.provCityQry();
},
methods:{
checkToken(){
api.checkToken().then(res=>{
if(res['success']){}else{
api.obtainToken().then(res=>{
if(res.success){
uni.setStorageSync('uni-token',res.data['token']);
}
})
}
})
},
radioChange: function(evt) {
for (let i = 0; i < this.chartsLegends.length; i++) {
if (this.chartsLegends[i].value === evt.detail.value) {
this.chartsLegendsCurrent = evt.detail.value;
this.drawLine(this.chartsLegendsCurrent)
break;
}
}
},
/*
num:源数据
digitNum:保留几位小数
type:向上(1)取还是向下(2)取
*/
formatFloat(num,digitNum=2,type=1){
return common.formatFloat(num,digitNum=2,type=1)
},
viewPlanningParams(){
// 查看规划参数
this.paramsSelected=this.dialogIsShow=true;
this.isLoanSelected = false;
this.cityInfo['isNew'] = '1';
if(this.housePurchaseInfo.preOrderSize <= 90){
this.cityInfo['area'] = '1'
}else if(this.housePurchaseInfo.preOrderSize <= 144){
this.cityInfo['area'] = '2'
}else{
this.cityInfo['area'] = '3'
}
this.planningParams = {
...this.planningParams,
downPaymentMin: this.housePurchaseInfo.downPaymentMin
}
},
getFollowData(e){
this.isNeedOfficialAccountQrcode= ref(e);
},
getPlanParams(e){
// console.log('规划参数子组件传过来的====',e)
this.planningParams = e;
this.housePurchaseInfo.downPaymentMin = this.planningParams['downPaymentMin'];
this.housePurchaseInfo.cityCode = this.housePurchaseInfo.cityId = this.planningParams['cityId'];
this.housePurchaseInfo.provinceCode = this.planningParams['provinceId'];
this.housePurchaseInfo.provinceName = this.planningParams['provinceName'];
this.housePurchaseInfo.cityName = this.planningParams['cityName'];
// 从规划参数弹窗获取数据
this.closeBtn()
},
editParams(){
this.dialogIsShow = this.isEditFlag = true;
},
getData(e){
this.dataLists = toRefs(e);
this.accumulationFundParams = this.dataLists.a;
this.commercialLoansParams = this.dataLists.b;
this.dialogIsShow = false;
// console.log('父组件拿到公积金贷款的值了',this.accumulationFundParams);
// console.log('父组件拿到商业贷款值了',this.commercialLoansParams);
this.houseLoanOldList = this.dataLists.c;
// console.log(this.houseLoanOldList)
},
onchange(e) {
const value = e.detail.value;
},
onnodeclick(node) {
this.cityInfo = {
cityId: node.parent_value ? node.value : null,
provinceId:node.parent_value ? node.parent_value : node.value,
}
this.queryCommercialHousingPrice();
},
drawLine(type=1) {
// 1是总房价
// 3是首付
// 4是总贷款
// 基于准备好的dom,初始化echarts实例
this.myChart = echarts.init(document.getElementById('myEcharts'));
// 绘制图表
let list1;
let showLists;
let dataOption = ['可实现的', '你想要的', '差额'];
if(this.housePurchasePrices.length){
if(type){
list1 = this.housePurchasePrices.filter((item)=>{
return item.priceType == type
})[0];
this.isNeedDis = list1.pvDifference>0;
if(list1.pvDifference>0){
showLists = [].concat(
this.formatFloat(list1.pvPriceRealization / 10000,2,2),
this.formatFloat(list1.pvPriceDesired/10000,2,2),
{value:this.formatFloat(Math.abs(list1.pvDifference)/10000),
itemStyle:{color:'#ff0000'}})
}else{
showLists = [].concat(
this.formatFloat(list1.pvPriceRealization / 10000,2,2),
this.formatFloat(list1.pvPriceDesired/10000,2,2));
dataOption = ['可实现的', '你想要的']
}
}
}
this.myChart.setOption({
legend: {},
grid: {
left: '20%', // 调整这个属性
},
xAxis: {
data: dataOption,
axisTick:{//坐标轴刻度相关设置。
show: false,
},
},
yAxis: {},
series: [
{
name:'',
data: showLists,
type: 'bar',
label:{
show:true,
position:'inside'
}
}
]
});
},
provCityQry(){
api.provCityQry({insurerId:888}).then((res)=>{
if(res['success']){
this.provinceList = common.action(res['data']['provinces']);
}
})
},
housePurchase(id){
this.housePurchaseInfo.housePurchaseType = id;
},
startCount(){
if(!this.housePurchaseInfo.nyear){
common.errorDialog(1,'请填写几年后购房')
return false;
}else{
if(this.housePurchaseInfo.nyear <= 0 || this.housePurchaseInfo.nyear >30){
common.errorDialog(1,'购房测算建议预估购房年数不超过30')
return false;
}
}
if(!this.housePurchaseInfo.provinceCode || !this.housePurchaseInfo.cityCode){
common.errorDialog(1,'请选择预购城市')
return false;
}
if(!this.housePurchaseInfo.preOrderSize){
common.errorDialog(1,'请填写预购面积')
return false;
}else{
if(this.housePurchaseInfo.preOrderSize>1000){
common.errorDialog(1,'住房面积一般不会超过1000㎡')
return false;
}
}
if(!this.housePurchaseInfo.targetPrice){
common.errorDialog(1,'请填写预购房产现在市场单价')
return false;
}
if(!this.housePurchaseInfo.downPaymentMin){
common.errorDialog(1,'请填写首付款最低成数')
return false;
}else{
if(this.housePurchaseInfo.downPaymentMin>100 || this.housePurchaseInfo.downPaymentMin < 0){
common.errorDialog(1,'首付款最低成数不应超过100%,且不应少于0')
return false;
}
}
if(!this.housePurchaseInfo.newLoanYear){
common.errorDialog(1,'请填写新房贷款年限')
return false;
}else {
if(this.housePurchaseInfo.newLoanYear<0 || this.housePurchaseInfo.newLoanYear>30){
common.errorDialog(2,'新房贷款年限最长不超过30年')
return false;
}
}
if(!this.housePurchaseInfo.interestRate){
common.errorDialog(1,'请填写新房贷款年利率')
return false;
}else{
if(this.housePurchaseInfo.interestRate > 24){
common.errorDialog(1,'新房贷款年利率不应超过24%')
return false;
}
}
if(!this.housePurchaseInfo.housePurchaseType){
common.errorDialog(1,'请填写购房用途')
return false;
}
if(!this.housePurchaseInfo.firstHouseAmount){
common.errorDialog(1,'请填写已备首付')
return false;
}
if(!this.housePurchaseInfo.repaymentSpecial){
common.errorDialog(1,'请填写每年投入房产资金')
return false;
}
// 规划参数默认值
const palnningParamsDefault = {
acceptableLossRate: 0.1,
downPaymentMin: 30,
houseDepreciationRate: 0.02,
housePriceGrowthRate: 0.0532,
incomeRate: 0,
tnvestmentRate: 0.0374
}
const param = {
...palnningParamsDefault,
...this.housePurchaseInfo,
...this.planningParams,
interestRate:this.housePurchaseInfo.interestRate / 100,
houseLoanOldList:this.isDisplace ? this.houseLoanOldList : null,
businessNo: nanoid(),
calcuteType:0,
decimal:4,
systemType:1,
userId:uni.getStorageSync('cffp_userId')
}
api.housePurchasePlanAnalysis(param).then((res)=>{
if(res['success']){
this.resultFlag = true;
this.resultInfos = res['data'];
this.housePurchasePrices = res['data']['housePurchasePrices'];
if(this.housePurchasePrices.length>0){
this.tipsPrice = this.housePurchasePrices.filter((item)=>{
return item.priceType == 2;
})[0]['fvPriceRealization'];
this.tipsTotalPrice = this.housePurchasePrices.filter((item)=>{
return item.priceType == 1;
})[0]['fvPriceRealization'];
}
setTimeout(()=>{
this.drawLine(this.chartsLegendsCurrent)
});
}else{
if(res['data']['code']==='E000'){
this.isNeedOfficialAccountQrcode = true;
return false;
}
common.errorDialog(2,res['message'])
}
})
},
onchange(e) {
const value = e.detail.value;
if(value.length>0){
this.housePurchaseInfo.provinceName = value[0]['text'];
this.housePurchaseInfo.provinceCode = value[0]['value'];
this.housePurchaseInfo.cityCode = value[1]['value'];
this.housePurchaseInfo.cityName = value[1]['text'];
}else{
this.housePurchaseInfo.provinceName = this.housePurchaseInfo.provinceCode =
this.housePurchaseInfo.cityCode = this.housePurchaseInfo.cityName = null;
}
},
closeBtn(){
// this.isLoanSelected = this.paramsSelected =
this.dialogIsShow = false;
},
//打开房屋置换组件
openLoan(){
this.isDisplace = !this.isDisplace;
if(this.isDisplace){
this.isLoanSelected = this.dialogIsShow = true;
this.paramsSelected = false;
}else{
this.dataLists = null;
}
},
getResultTitle(priceType){
if(priceType === '1'){
return '房屋总价';
}else if(priceType === '2'){
return '房屋单价';
}else if(priceType === '3'){
return '首付款';
}else if(priceType === '4'){
return '贷款金额';
}
},
// 数字千分位处理
numberConverter(val){
return dataHandling.numberConverter(val)
},
// 获取房价增长率
queryCommercialHousingPrice(){
if(this.housePurchaseInfo.preOrderSize <= 90){
this.cityInfo['area'] = '1'
}else if(this.housePurchaseInfo.preOrderSize <= 144){
this.cityInfo['area'] = '2'
}else{
this.cityInfo['area'] = '3'
}
this.cityInfo = {
...this.cityInfo,
isNew:1,
}
api.queryCommercialHousingPrice(this.cityInfo).then(res=>{
if(res['success']){
const result = res['data']['priceInfo']['rateB'];
const power = result.toString().indexOf('.') > -1 ? result.toString().substring(result.toString().indexOf('.')+1).length : 0;
this.planningParams.housePriceGrowthRate = (res['data']['priceInfo']['rateB']) * (Math.pow(10,power)) / (Math.pow(10,power+2)) ;
}
})
},
resetData(){
this.housePurchaseInfo = {
nyear:null,//几年后购房
provinceCode:null,
provinceName:null,
cityCode:null,
cityName:null,
preOrderSize:null,//预购面积
targetPrice:null,//目标价格(现值)
downPaymentMin:null,//首付款最低成数(百分位)
newLoanYear:null,//新房贷款年限【必须大于0】
firstHouseAmount:null,//初期购房资金(单位万)
housePurchaseType:null,//购房用途
repaymentSpecial:null,//每年还贷专用款(单位万)
interestRate:null, //贷款年利率
};
this.houseLoanOldList = [];
this.planningParams = {};
this.resultFlag = false;
}
},
mounted() {
this.checkToken();
}
}
</script>
<style scoped lang="scss">
@import '../sfpCommon.css';
.wrapper{
.houseInfo .title{
padding-left: 0;
justify-content: space-between;
.editParam{
font-size: 26rpx;
color: #666;
border: 1px solid #CEB07D;
padding: 4rpx 16rpx;
border-radius: 6rpx;
font-weight: normal;
}
}
.houseInfo .title::before{
width: 0;
}
.inputItem {
.inputContent {
label{
text-align: right;
white-space: nowrap;
}
}
.btn_wrapper{
display: flex;
.btn_item{
width: 100rpx;
padding:5rpx 0;
border: 1px solid #CEB07D;
margin-right: 10rpx;
text-align: center;
position: relative;
font-size: 26rpx;
color: #333;
}
.btn_wrapper .btn_item:last-child{
margin-right: 0;
}
.btn_item.selected{
color:#FED495;
}
// .selected:after{
// display:block;
// content:'';
// border-width:20rpx 20rpx 20rpx 20rpx;
// border-style:solid;
// border-color:#FED495 transparent transparent transparent;
// position:absolute;
// right: -20rpx;
// transform: rotate(-45deg);
// bottom: -11.5px;
// }
}
}
.title .view{
color: #666;
border: 1px #FED495 solid;
font-weight: normal;
padding:8rpx 20rpx;
font-size: 28rpx;
width: 110rpx;
text-align: center;
}
.result_wrapper{
.resultSummaryContent{
background: #FFDBD4;
border-radius: 3px;
padding: 8px 20px;
box-shadow: 3px 1px 4px 0 rgb(0 0 0 / 25%);
margin: 20px 0;
font-size: 18px;
}
.seriesNo{
width: 0;
height: 40rpx;
border-radius: 50%;
background: #f07006;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
flex: 0 0 40rpx;
margin-right: 10rpx;
margin-top: 8rpx;
}
.line{
border-radius: 10rpx;
box-shadow: 0 0 5px #969696;
background: #fff;
margin: 20rpx 0;
padding: 0 10rpx 20rpx 10rpx;
position: relative;
.line_title{
background: linear-gradient(135deg, #CEB07D 0%, #FFDDA9 56%, #FED495 100%, #FED495 100%);
color: #fff;
width: 40%;
border-radius: 10rpx 0 10rpx 0;
text-align: center;
padding: 10rpx 0;
margin-left: -10rpx;
img{
position: absolute;
right: 0;
max-width: 17%;
top: 3%;
}
}
.content{
display: flex;
color: #fff;
justify-content: space-around;
margin: 20rpx 0;
align-items: center;
.left,.right{
background: #1349DD;
border-radius: 8rpx;
display: flex;
flex-direction: column;
align-items: center;
width: 48%;
box-shadow: 0 1px 1px #969696;
padding-bottom: 20rpx;
view {
margin: 10rpx;
}
}
img{
max-width: 15%;
}
.right{
background: #F07006;
}
.left .realizable,.right .realizable{
width: 60%;
background: #fff;
border-radius: 0 0 10rpx 10rpx;
text-align: center;
padding: 10rpx 0;
margin: 0;
}
.left .realizable{
color:#1349DD;
}
.right .realizable{
color:#F07006;
}
}
.line_bottom{
background: #e9ffe6;
color: #666;
width: 98%;
padding: 10rpx;
}
.line_bottom.fail{
background: #ffe6e6;
}
}
}
}
.chartsLegend{
button{
margin-right: 6rpx;
}
}
.mask{
position: fixed;
left: 0;
top: 0;
width:100%;
height:100%;
background:rgba(0,0,0,.35);
z-index: 2;
.content{
position: relative;
width: 95%;
height: 60vh;
margin: 10% auto;
border-radius: 0.3125rem;
background-color: #fff;
overflow-y: scroll;
box-shadow: 0 1px 5px 2px #8b8b8b;
padding-top: 70rpx;
.closeBtn{
position: absolute;
right: 20rpx;
top: 20rpx;
}
}
}
</style>
\ No newline at end of file
<template>
<div class="mortgageCalculatorContainer">
<view class="tabTitle" v-if="!isReadonly">
<view v-for="item of loanTypeLists">
<text :class="{ actived: item.value===loanType }" @click="selectLoanType(item.value)">{{item.text}}</text>
</view>
</view>
<view>
<!-- 公积金贷款 -->
<view class="accumulationFundContainer" v-if="loanType==2 || loanType==3">
<h5 v-if="!isReadonly">公积金</h5>
<ul>
<li v-for="item of accumulationFundParams" :key="item.id">
<div>{{item.text}}</div>
<div v-if="item.type==='number' || item.type==='digit'">
<input class="uni-input" type="{{item.type}}" v-model="item.value" placeholder="请输入" :disabled="isReadonly"/>
<span>{{item.unit}}</span>
</div>
<div v-else-if="item.type==='select'" style="width:55%">
<view class="btn_wrapper">
<button class="min-btn" @click="item.value=listItem.value" :class="{actived:item.value==listItem.value}" type="default" plain="true" v-for="listItem of repaymentMethodLists">{{listItem.text}}</button>
</view>
</div>
</li>
</ul>
</view>
<!-- 商业贷款 -->
<view class="commercialLoans" v-if="loanType=='1'|| loanType=='3'">
<h5 v-if="!isReadonly">商业贷款</h5>
<ul>
<li v-for="item of commercialLoansParams" :key="item.id">
<div>{{item.text}}</div>
<div v-if="item.type==='number' || item.type==='digit'">
<input class="uni-input" type="{{item.type}}" v-model="item.value" placeholder="请输入" :disabled="isReadonly"/>
<span>{{item.unit}}</span>
</div>
<div v-else-if="item.type==='select'" style="width:55%">
<view class="btn_wrapper">
<button class="min-btn" @click="item.value=listItem.value" :class="{actived:item.value==listItem.value}" type="default" plain="true" v-for="listItem of repaymentMethodLists">{{listItem.text}}</button>
</view>
</div>
</li>
</ul>
</view>
</view>
<view class="footer" v-if="!isReadonly">
<view @click="save()" class="save">保存</view>
<view @click="clear()" class="clear">清空</view>
</view>
</div>
</template>
<script>
import { ref,toRefs,reactive } from "vue";
export default{
props: ['isReadonly','loanType','a','b'],
emits:['getData'],
data(){
return{
accumulationFundParams:[
{id:'00',text:'公积金贷款余额',value:null,type:'digit',unit:'万元',alias:'oldHouseLoanBalance'},
{id:'01',text:'公积金还款方式',value:1,type:'select',unit:'',alias:'oldCalcuteType'},
{id:'02',text:'公积金剩余月份',value:null,type:'number',unit:'月',alias:'oldHouseRepaymentMonth'},
{id:'03',text:'公积金年利率',value:null,type:'digit',unit:'%',alias:'oldInterestRate'},
],
commercialLoansParams:[
{id:'00',text:'商业贷款余额',value:null,type:'digit',unit:'万元',alias:'oldHouseLoanBalance'},
{id:'01',text:'商业还款方式',value:1,type:'select',unit:'',alias:'oldCalcuteType'},
{id:'02',text:'商业贷款剩余月份',value:null,type:'number',unit:'月',alias:'oldHouseRepaymentMonth'},
{id:'03',text:'商业贷款年利率',value:null,type:'digit',unit:'%',alias:'oldInterestRate'},
],
loanTypeLists:[
{id:'00',text:'商业贷款',value:1},
{id:'01',text:'公积金贷款',value:2},
{id:'02',text:'组合贷款',value:3}
],
repaymentMethodLists:[{id:'00',text:'等额本金',value:1},{id:'01',text:'等额本息',value:2}],
houseLoanOldList:[],
loadInfo:{
oldHouseLoanBalance:null, //旧房贷款余额(单位万)
oldHouseRepaymentMonth:null, //旧房贷款剩余月份
oldInterestRate:null,//旧房贷款利率
oldCalcuteType:1, //旧房还款计算方式 【1:等额本息】与【2:等额本金】 【必填】
oldLoanType:null, //旧房贷款计算方式 【1:商业贷款】与【2:公积金贷款】【必填】
oldIsPortfolioLoan:null //旧房是否组合贷 【1:是】与【2:否】【必填】
}
}
},
name:'loanBalance',
components:{
},
setup(props,content) {
console.log('子组件拿到值了',props);
const a = reactive({value:props.a});
const b = reactive({value:props.b});
const loanType = ref(props.loanType);
const isReadonly = ref(props.isReadonly);
const sendData = (e) =>{
content.emit('getData',e);
}
console.log(a);
console.log(b)
return {loanType,sendData,a,b,isReadonly}
},
mounted(){
if(JSON.stringify(this.a.value) != '{}' && JSON.stringify(this.a.value) != '[]'){
this.accumulationFundParams = this.a.value
}
if(JSON.stringify(this.b.value) != '{}' && JSON.stringify(this.b.value) != '[]'){
this.commercialLoansParams = this.b.value;
}
if(!(this.accumulationFundParams.findIndex(item=>item.value==null || item.value == '') >= 0) && !(this.commercialLoansParams.findIndex(item=>item.value==null || item.value == '') >= 0)){
this.loanType = 3;
}else if(!(this.accumulationFundParams.findIndex(item=>item.value==null || item.value == '') >= 0)){
this.loanType = 2;
}else{
this.loanType = 1;
}
},
methods:{
clear(){
this.accumulationFundParams=[
{id:'00',text:'公积金贷款余额',value:null,type:'digit',unit:'元',alias:'oldHouseLoanBalance'},
{id:'01',text:'公积金还款方式',value:1,type:'select',unit:'',alias:'oldCalcuteType'},
{id:'02',text:'公积金剩余月份',value:null,type:'number',unit:'月',alias:'oldHouseRepaymentMonth'},
{id:'03',text:'公积金年利率',value:null,type:'digit',unit:'%',alias:'oldInterestRate'},
];
this.commercialLoansParams=[
{id:'00',text:'商业贷款余额',value:null,type:'digit',unit:'元',alias:'oldHouseLoanBalance'},
{id:'01',text:'商业还款方式',value:1,type:'select',unit:'',alias:'oldCalcuteType'},
{id:'02',text:'商业贷款剩余月份',value:null,type:'number',unit:'月',alias:'oldHouseRepaymentMonth'},
{id:'03',text:'商业贷款年利率',value:null,type:'digit',unit:'%',alias:'oldInterestRate'},
];
},
selectLoanType(e){
if(this.loanType != e){
this.loanType = e;
this.clear();
}
},
errorDialog(type,content){
// type 1 必填项校验 2 规则校验
uni.showModal({
title: type===1 ? '必填项校验' : '规则校验',
content:content,
showCancel:false,
success: function (res) {
if (res.confirm) {
console.log('用户点击确定');
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
},
save(){
let houseLoanOldInfo = {
oldLoanType:this.loanType,
oldIsPortfolioLoan:this.loanType === 3 ? 1 : 2,
oldHouseLoanBalance:null,
oldHouseRepaymentMonth:null,
oldInterestRate:null,
oldCalcuteType:null
};
let houseLoanOldInfo1 = {
oldLoanType:this.loanType,
oldIsPortfolioLoan:this.loanType === 3 ? 1 : 2,
oldHouseLoanBalance:null,
oldHouseRepaymentMonth:null,
oldInterestRate:null,
oldCalcuteType:null
};
if(this.loanType===1){
this.houseLoanOldList = [];
// 商业贷款
for(let i=0;i<this.commercialLoansParams.length;i++){
if(!this.commercialLoansParams[i].value){
this.errorDialog(1,`${this.commercialLoansParams[i].text}为必填项`);
return;
}else if(this.commercialLoansParams[i].value < 0 || isNaN(this.commercialLoansParams[i].value) ){
this.errorDialog(2,`${this.commercialLoansParams[i].text}必须为大于0的数字`);
return;
}else if(this.commercialLoansParams[i].alias==='oldInterestRate'){
if(this.commercialLoansParams[i].value > 100){
this.errorDialog(2,`${this.commercialLoansParams[i].text}必须小于100`);
return;
}
}else if(this.commercialLoansParams[i].alias==='oldHouseRepaymentMonth'){
if(this.commercialLoansParams[i].value > 360){
this.errorDialog(2,`${this.commercialLoansParams[i].text}必须小于360`);
return;
}
}
}
houseLoanOldInfo.oldHouseLoanBalance = this.commercialLoansParams.filter(item=>item.alias==='oldHouseLoanBalance').pop().value;
houseLoanOldInfo.oldHouseRepaymentMonth= this.commercialLoansParams.filter(item=>item.alias==='oldHouseRepaymentMonth').pop().value;
houseLoanOldInfo.oldInterestRate= this.commercialLoansParams.filter(item=>item.alias==='oldInterestRate').pop().value/100;
houseLoanOldInfo.oldCalcuteType = this.commercialLoansParams.filter(item=>item.alias==='oldCalcuteType').pop().value;
houseLoanOldInfo.oldHouseNo = 1;
this.houseLoanOldList = [houseLoanOldInfo];
}else if(this.loanType===2){
// 公积金贷款
for(let i=0;i<this.accumulationFundParams.length;i++){
this.houseLoanOldList=[];
if(!this.accumulationFundParams[i].value){
this.errorDialog(1,`${this.accumulationFundParams[i].text}为必填项`);
return;
}else if(this.accumulationFundParams[i].value < 0 || isNaN(this.accumulationFundParams[i].value)){
this.errorDialog(2,`${this.accumulationFundParams[i].text}必须为大于0的数字`);
return;
}else if(this.accumulationFundParams[i].alias==='oldInterestRate'){
if(this.accumulationFundParams[i].value > 100){
this.errorDialog(2,`${this.accumulationFundParams[i].text}必须小于100`);
return;
}
}else if(this.accumulationFundParams[i].alias==='oldHouseRepaymentMonth'){
if(this.accumulationFundParams[i].value > 360){
this.errorDialog(2,`${this.accumulationFundParams[i].text}必须小于360`);
return;
}
}
}
houseLoanOldInfo.oldHouseLoanBalance = this.accumulationFundParams.filter(item=>item.alias==='oldHouseLoanBalance').pop().value;
houseLoanOldInfo.oldHouseRepaymentMonth= this.accumulationFundParams.filter(item=>item.alias==='oldHouseRepaymentMonth').pop().value;
houseLoanOldInfo.oldInterestRate= this.accumulationFundParams.filter(item=>item.alias==='oldInterestRate').pop().value/100;
houseLoanOldInfo.oldCalcuteType = this.accumulationFundParams.filter(item=>item.alias==='oldCalcuteType').pop().value;
houseLoanOldInfo.oldHouseNo = 1;
this.houseLoanOldList = [houseLoanOldInfo];
}else{
// 组合贷款
// 公积金贷款
for(let i=0;i<this.accumulationFundParams.length;i++){
if(!this.accumulationFundParams[i].value){
this.errorDialog(1,`${this.accumulationFundParams[i].text}为必填项`);
return;
}else if(this.accumulationFundParams[i].value < 0 || isNaN(this.accumulationFundParams[i].value)){
this.errorDialog(2,`${this.accumulationFundParams[i].text}必须为大于0的数字`);
return;
}else if(this.accumulationFundParams[i].alias==='oldInterestRate'){
if(this.accumulationFundParams[i].value > 100){
this.errorDialog(2,`${this.accumulationFundParams[i].text}必须小于100`);
return;
}
}else if(this.accumulationFundParams[i].alias==='oldHouseRepaymentMonth'){
if(this.accumulationFundParams[i].value > 360){
this.errorDialog(2,`${this.accumulationFundParams[i].text}必须小于360`);
return;
}
}
}
// 商业贷款
for(let i=0;i<this.commercialLoansParams.length;i++){
if(!this.commercialLoansParams[i].value){
this.errorDialog(1,`${this.commercialLoansParams[i].text}为必填项`);
return;
}else if(this.commercialLoansParams[i].value < 0 || isNaN(this.commercialLoansParams[i].value)){
this.errorDialog(2,`${this.commercialLoansParams[i].text}必须为大于0的数字`);
return;
}else if(this.commercialLoansParams[i].alias==='oldInterestRate'){
if(this.commercialLoansParams[i].value > 100){
this.errorDialog(2,`${this.commercialLoansParams[i].text}必须小于100`);
return;
}
}else if(this.commercialLoansParams[i].alias==='oldHouseRepaymentMonth'){
if(this.commercialLoansParams[i].value > 360){
this.errorDialog(2,`${this.commercialLoansParams[i].text}必须小于360`);
return;
}
}
}
houseLoanOldInfo.oldHouseLoanBalance = this.commercialLoansParams.filter(item=>item.alias==='oldHouseLoanBalance').pop().value;
houseLoanOldInfo.oldHouseRepaymentMonth= this.commercialLoansParams.filter(item=>item.alias==='oldHouseRepaymentMonth').pop().value;
houseLoanOldInfo.oldInterestRate= this.commercialLoansParams.filter(item=>item.alias==='oldInterestRate').pop().value/100;
houseLoanOldInfo.oldCalcuteType = this.commercialLoansParams.filter(item=>item.alias==='oldCalcuteType').pop().value;
houseLoanOldInfo.oldLoanType = 1;
houseLoanOldInfo.oldHouseNo = 1;
houseLoanOldInfo1.oldHouseLoanBalance = this.accumulationFundParams.filter(item=>item.alias==='oldHouseLoanBalance').pop().value;
houseLoanOldInfo1.oldHouseRepaymentMonth= this.accumulationFundParams.filter(item=>item.alias==='oldHouseRepaymentMonth').pop().value;
houseLoanOldInfo1.oldInterestRate= this.accumulationFundParams.filter(item=>item.alias==='oldInterestRate').pop().value/100;
houseLoanOldInfo1.oldCalcuteType = this.accumulationFundParams.filter(item=>item.alias==='oldCalcuteType').pop().value;
houseLoanOldInfo1.oldLoanType = 2;
houseLoanOldInfo.oldHouseNo = 1;
this.houseLoanOldList = [houseLoanOldInfo,houseLoanOldInfo1];
}
// 旧房贷款信息集合
// console.log(this.houseLoanOldList)
const ab = {
a:this.accumulationFundParams,
b:this.commercialLoansParams,
c:this.houseLoanOldList
}
this.sendData(ab)
},
}
}
</script>
<style lang="scss">
.mortgageCalculatorContainer{
padding: 0 20rpx 70rpx;
position: relative;
.tabTitle{
display: flex;
margin-bottom: 30rpx;
view{
width: 0;
flex: 1;
text-align: center;
text{
position: relative;
&.actived{
color: #6B4000;
&::after{
content:'';
position:absolute;
bottom: -2px;
left: 0;
width: 100%;
height: 4rpx;
background: linear-gradient(125deg, rgba(206, 176, 125, 1), rgba(254, 213, 151, 1));
}
}
}
}
}
ul{
li{
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #E4E4E4;
height:80rpx;
>div:last-child{
display: flex;
text-align: right;
span{
padding-left: 10rpx;
}
.btn_wrapper{
display: flex;
width: 100%;
.min-btn{
position: relative;
flex: 1;
width: 0;
margin-left: 10rpx;
line-height: 1.8;
font-size: 26rpx;
border-radius: 6rpx;
border: 1px solid #CEB07D;
&.actived{
color: #6B4000;
}
&.actived::before{
display: block;
content: "";
position: absolute;
right: 0;
bottom: 0;
width: 0;
height: 0;
border: 18rpx solid #fed9a1;
border-top-color: transparent;
border-left-color: transparent;
}
}
}
}
}
}
h5{
position: relative;
color: #CEB07D;
font-size: 32rpx;
padding-left: 20rpx;
margin-top: 20rpx;
&::before{
content:'';
position:absolute;
left: 0;
top: 50%;
width: 8rpx;
height: 20rpx;
transform: translateY(-50%);
background: linear-gradient(123deg, #CEB07D 0%, #FED495 100%, #D1B27E 100%);
border-radius: 8rpx;
opacity: 1;
}
}
.footer{
position: relative;
margin: 20px auto;
display: flex;
justify-content: center;
.save{
width: 300rpx;
height: 80rpx;
background: linear-gradient(135deg, #CEB07D 0%, #FFDDA9 56%, #FED495 100%, #FED495 100%);
border-radius: 4px;
font-size: 36rpx;
color: #6B4000;
font-weight: 500;
display: flex;
justify-content: center;
align-items: center;
}
.clear{
position: absolute;
right: 0;
bottom: 0;
border-bottom: 1px solid #000;
padding: 0 10rpx;
}
}
}
</style>
\ No newline at end of file
<template>
<view class="paramsContainer">
<h5>规划参数<span>(点击参数值即可修改参数)</span></h5>
<view class="ulBox">
<template v-for="item in editParamLists">
<view :key="item.id" v-if="item.isShow" class="liBox">
<view>
<view class="paramName">{{item.name}}</view>
<view class="paramValue">
<input class="uni-input" type="digit" min='1' maxlength="17" placeholder="" v-model.trim="item.value"/>
<span>%</span>
</view>
<view class="dataSelect">
<view v-if="item.type==='data-picker'">
<view>
<uni-data-picker v-model="cityId" :localdata="provinceList" popup-title="请选择城市" @change="onchange" @nodeclick="onnodeclick"></uni-data-picker>
</view>
</view>
</view>
</view>
<view v-if="item.remark" class="tips">
<view>
<text style="font-size: 24rpx;color: #c0c4cc;">{{item.remark}}</text>
</view>
</view>
</view>
</template>
</view>
<view class="optionContent">
<view class="confirm"><text @click="confirmParams()">确定</text></view>
<view class="reset"><text @click="resetParams()">恢复默认</text></view>
</view>
</view>
</template>
<script>
import {toRefs} from "vue";
import api from '../../api/api';
import common from '../../common/common'
export default{
props:['cityInfo','planningParams'],
emits:['getData'],
data(){
return {
cityId:null,
paramsLists:[
{id:'01',name:'房价增长率',value:5.32,type:'data-picker',remark:'',alias:'housePriceGrowthRate',isShow:true },
{id:'02',name:'房屋折旧率',value:2,type:'number',remark:'',alias:'houseDepreciationRate',isShow:true},
{id:'03',name:'首付款最低成数',value:30,type:'number',remark:'',alias:'downPaymentMin',isShow:true},
{id:'05',name:'资产投资回报率',value:3.74,type:'number',remark:'',alias:'tnvestmentRate',isShow:true},
{id:'06',name:'投入资金增长率',value:0,type:'number',remark:'"每年投入房产资金"将会按照该设定值进行增长型测算',alias:'incomeRate',isShow:true},
{id:'07',name:'可接受本金损失',value:10,type:'number',remark:'',alias:'acceptableLossRate',isShow:true}
],
editParamLists:[],
provinceList:[],
}
},
name:'planningParameters',
components:{
},
onLoad(){
},
setup(props,content){
const cityInfo = props.cityInfo ? props.cityInfo : null;
const planningParams = props.planningParams ? toRefs(props.planningParams) : null;
const sendData = (e) =>{
content.emit('getData',e);
}
return {sendData,cityInfo,planningParams}
},
methods:{
onchange(e) {
// const value = e.detail.value;
},
onnodeclick(node) {
this.cityInfo = {
...this.cityInfo,
cityId: node.value,
provinceId:node.parent_value ? node.parent_value : null,
cityName:node.parent_value ? node.text : this.cityInfo.cityName,
provinceName:node.parent_value ? this.cityInfo.provinceName : node.text,
}
this.queryCommercialHousingPrice()
},
resetParams(){
this.editParamLists = JSON.parse(JSON.stringify(this.paramsLists));
this.cityId=null;
this.cityInfo = {cityId:null,provinceId:null,cityName:null,provinceName:null};
},
provCityQry(){
api.provCityQry({insurerId:888}).then((res)=>{
if(res['success']){
this.provinceList = common.action(res['data']['provinces']);
}
})
},
confirmParams(){
for(let i=0;i<this.editParamLists.length;i++){
if(this.editParamLists[i].alias==='tnvestmentRate' && this.editParamLists[i].value>2000){
common.errorDialog(1,`${this.editParamLists[i].name}一般最高不超过2000`) ;
return false;
}
if(this.editParamLists[i].value>100){
common.errorDialog(1,`${this.editParamLists[i].name}最高不应超过100`) ;
return false;
}
}
const params = {
housePriceGrowthRate:(this.editParamLists.filter(item=>item.alias==='housePriceGrowthRate')[0].value / 100).toFixed(4),//房价增长率
houseDepreciationRate:(this.editParamLists.filter(item=>item.alias==='houseDepreciationRate')[0].value / 100).toFixed(4),//房屋折旧率
downPaymentMin:this.editParamLists.filter(item=>item.alias==='downPaymentMin')[0].value,//首付款最低成数(百分位)
tnvestmentRate:(this.editParamLists.filter(item=>item.alias==='tnvestmentRate')[0].value / 100).toFixed(4),//投资回报率
incomeRate:(this.editParamLists.filter(item=>item.alias==='incomeRate')[0].value / 100).toFixed(4),//收入增长率
acceptableLossRate:(this.editParamLists.filter(item=>item.alias==='acceptableLossRate')[0].value / 100).toFixed(4),//可接受本金损失率,
cityId:this.cityInfo.cityId,
provinceId:this.cityInfo.provinceId,
provinceName:this.cityInfo.provinceName,
cityName:this.cityInfo.cityName,
}
this.sendData(params)
},
// 获取房价增长率
queryCommercialHousingPrice(){
api.queryCommercialHousingPrice(this.cityInfo).then(res=>{
if(res['success']){
this.editParamLists.find(item=>item.alias==='housePriceGrowthRate')['value'] = res['data']['priceInfo']['rateB'];
}
})
}
},
mounted() {
this.editParamLists = JSON.parse(JSON.stringify(this.paramsLists));
if(!(JSON.stringify(this.planningParams) == '{}')){
const result = this.planningParams;
this.editParamLists.map(item=>{
if(result[item.alias] && result[item.value]){
item.value = result['downPaymentMin'].value;
// 首付成数不需要换算
if(item.alias !== 'downPaymentMin'){
if(result[item.alias].value){
item.value = result[item.alias].value * 100
}
}
}
})
}
this.provCityQry();
this.cityId = this.cityInfo.cityId;
this.queryCommercialHousingPrice()
}
}
</script>
<style lang="scss">
.paramsContainer{
background-color: #fff;
padding: 0 20rpx 44rpx;
h5{
position: relative;
color: #CEB07D;
font-size: 32rpx;
padding-left: 20rpx;
margin-bottom: 40rpx;
span{
font-size: 26rpx;
font-weight: normal;
}
&::before{
content:'';
position:absolute;
left: 0;
top: 50%;
width: 8rpx;
height: 20rpx;
transform: translateY(-50%);
background: linear-gradient(123deg, #CEB07D 0%, #FED495 100%, #D1B27E 100%);
border-radius: 8rpx;
opacity: 1;
}
}
.liBox{
padding: 16rpx 0;
border-bottom: 1px solid #E4E4E4;
view{
display: flex;
align-items: center;
.paramName{
color: #6B4000;
font-size: 30rpx;
font-weight: bold;
width: 0;
flex: 0 0 35%;
letter-spacing: 1px;
}
.paramValue{
color: #CEB07D;
font-size: 0.8125rem;
font-weight: bold;
display: flex;
width: 0;
flex: 0 0 20%;
align-items: center;
text-align: right;
}
.dataSelect{
width: 0;
flex: 0 0 40%;
}
}
}
.optionContent{
height: 94rpx;
line-height: 94rpx;
position: relative;
margin-top: 40rpx;
view{
&.confirm{
padding: 0 50px;
box-shadow: 0px 2px 2px 1px rgb(0 0 0 / 35%);
background:linear-gradient(to bottom right,#CEB07D,#FED597);
}
text{
font-size: 36rpx;
font-weight: bold;
color: #6B4000;
letter-spacing: 2px;
}
&.reset{
position: absolute;
right: 0;
bottom: 0;
span{
color: #CEB07D;
background-image:linear-gradient(to bottom right,#CEB07D,#FED597);
background-clip:text;
color:transparent;
font-size:26rpx;
border-bottom: 1px solid #CEB07D;
}
}
}
}
.closeBtn{
position: absolute;
right: 20rpx;
top: 20rpx;
}
}
</style>
\ No newline at end of file
.batchCalculateContent{
display: flex;
flex-direction: column;
align-items: center;
}
.logo {
width: 100%;
}
.tabTitle{
display: flex;
justify-content: space-around;
font-size: 32rpx;
font-family: Source Han Sans CN-Regular, Source Han Sans CN;
font-weight: 400;
color: #333333;
}
.tabTitle text{
position: relative;
}
.tabTitle text.actived::after{
position: absolute;
bottom: -4rpx;
left: 0;
content: '';
width: 100%;
height: 4rpx;
background: linear-gradient(125deg,#CEB07D,#FED597);
}
.simpleDataResult{
background: #FFFFFF;
box-shadow: 0rpx 0rpx 11rpx 0rpx rgba(0,0,0,0.1);
border-radius: 5rpx;
opacity: 1;
margin: 30rpx 15rpx 56rpx;
padding: 15rpx 17rpx;
scroll-behavior:smooth;
}
.simpleDataResult .resultTitle{
font-size: 32rpx;
font-weight: bold;
color: #CEB07D;
flex: 1;
}
.simpleDataResult .calcNumber{
text-align: right;
font-size: 20px;
flex: 1;
}
.simpleDataResult .inputItem:last-child{
border:none;
}
.simpleDataResult .inputItem .title{
color: #CEB07D;
font-weight: bold;
}
.reduceInsuranceContent .tableTh,.reduceInsuranceContent .tableTd{
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16rpx;
}
.reduceInsuranceContent .tableTh text{
flex: 1;
}
.reduceInsuranceContent .tableTh text.withdrawNumber,.reduceInsuranceContent .tableTd text.withdrawNumber{
flex: 2;
}
.reduceInsuranceContent .tableTd .uni-input,.reduceInsuranceContent .tableTh text{
text-align: center;
border-bottom: 1px solid #E4E4E4;
padding: 6rpx 24rpx;
margin-right: 20rpx;
}
.reduceInsuranceContent .tableTh text{
border:none;
white-space: nowrap;
color: #333;
}
.reduceInsuranceContent .tableTd:last-child{
margin-bottom: 20rpx;
}
.resultContent{
margin-bottom: 60rpx;
padding-bottom: 60rpx;
}
.batchDataResult{
box-shadow: 0px 0px 11px 0px rgba(0,0,0,0.1);
margin-top: 32rpx;
}
.batchDataResult .resultTh{
height: 60rpx;
line-height: 60rpx;
background: linear-gradient(135deg, #CEB07D 0%, #FFDDA9 56%, #FED495 100%, #FED495 100%);
border-top-left-radius: 12rpx;
border-top-right-radius: 12rpx;
color: #6B4000;
font-weight: bold;
display: flex;
}
.batchDataResult .resultTd{
display: flex;
height: 60rpx;
align-items: center;
border-bottom: 1px solid #E4E4E4;
}
.batchDataResult .resultTd:last-child{
border-bottom: none;
}
.batchDataResult .resultTh text,.batchDataResult .resultTd text{
flex: 1;
text-align: center;
font-weight: bold;
color: #333333;
}
.batchDataResult .resultTd text.resultNumber{
color: #CEB07D;
}
/* .cashValueContent{
margin-top: 80rpx;
} */
.cashValueContent .title button{
background-color: transparent;
font-size: 30rpx;
color: #333333;
box-sizing: border-box;
line-height: initial;
}
.cashValueContent .title button::after{
border: 2px solid #CEB07D;
border-radius: 12rpx;
}
.cashValueContent .title button:first-child{
margin-right: 40rpx;
}
.cashValueContent .title button.actived{
background: linear-gradient(135deg, #CEB07D 0%, #FFDDA9 56%, #FED495 100%, #FED495 100%);
color: #6B4000;
}
.reduceInsuranceContent text{
display: inline-block;
width: 40rpx!important;
height: 40rpx!important;
line-height: 40rpx!important;
text-align: center;
font-size: 24rpx;
}
.qrcodeContainer{
width: 100%;
height: 100vh;
overflow: hidden;
}
.qrcodeContainer img{
max-width: 100%;
}
.tips{
position: absolute;
bottom: -30rpx;
left: 28rpx;
width: 100%;
font-size: 24rpx;
text-align: left;
color: red;
}
<template>
<!-- 已关注公众号用户 -->
<view class="content">
<view class="banner">
<image src="/static/images/policyIrrBanner.png" mode="widthFix"></image>
<!-- 使用说明 -->
<text @click="instructionForUse()">使用说明</text>
<commonHead></commonHead>
</view>
<scroll-view scroll-y="true" class="formInfoContainer" id="formInfoContainer">
<view class="tabTitle">
<text @click="switchTab('1')" :class="{ 'actived': calcuteType==='1' }">增额</text>
<text @click="switchTab('2')" :class="{ 'actived': calcuteType==='2' }">年金</text>
</view>
<form>
<!-- 保单信息 -->
<view class="policyInfoContent">
<view class="title">
<view>保单信息</view>
<!-- <button class="btn" style="font-size: 12px;margin: 0;padding: 0 30px;"
@click="calcute(2)"
>保存</button> -->
</view>
<view class="inputItem">
<text>交费年限:</text>
<view class="inputContent">
<input class="uni-input" type="number" placeholder="请输入"
v-model.trim="irrAndSimpleCalcuteParam.paymentPeriod" maxlength="3"
/><label for=""></label>
</view>
</view>
<view class="inputItem">
<text>年交保费:</text>
<view class="inputContent">
<input class="uni-input" type="digit" placeholder="请输入" maxlength="17"
v-model.trim="irrAndSimpleCalcuteParam.annualPremium"
/><label for=""></label>
</view>
</view>
<view class="inputItem" v-show="calcuteType==='2'">
<text>万能账户首年交费<text style="font-size: 24rpx;">(如有)</text></text>
<view class="inputContent">
<input class="uni-input" type="digit" placeholder="请输入" maxlength="17"
v-model.trim="irrAndSimpleCalcuteParam.allFirstPayment" @input="withdrawalTypeInit()"
/><label for=""></label>
</view>
</view>
</view>
<!-- 提领信息 -->
<view class="claimInfomationContent" v-if="!irrAndSimpleCalcuteParam.allFirstPayment || irrAndSimpleCalcuteParam.allFirstPayment=='' || irrAndSimpleCalcuteParam.allFirstPayment==0">
<view class="title">
<text>提领信息</text>
<view @click="changeWithdrawalType()" v-if="calcuteType=='1'">
<view style="display: flex;">
<view class="radioButton" :class="{'selected':!withdrawalType}"></view>
<text style="margin-left: 10rpx;">减保取现</text>
</view>
<view class="tips">
<text>(如有减保取现,请点击右侧按钮填写减保领取信息)</text>
</view>
</view>
</view>
<!-- 年金提领信息 -->
<view class="annuityContent" v-if="calcuteType==='2'">
<view v-for="item in yearWithdrawalInfos">
<view class="inputItem">
<text>从第几个保单年度开始提取:</text>
<view class="inputContent">
<input class="uni-input" type="number" placeholder="请输入" maxlength="3"
v-model="item.withdrawalStart"/><label for=""></label>
</view>
</view>
<view class="inputItem">
<text style="white-space: nowrap;">每年提取金额:</text>
<view class="inputContent">
<input class="uni-input" type="digit" placeholder="请输入" maxlength="17"
v-model="item.yearWithdrawalAmount" /><label for=""></label>
</view>
</view>
</view>
</view>
<!-- 增额减保取现 -->
<view class="reduceInsuranceContent" v-if="!withdrawalType && calcuteType==='1'">
<view class="tableTh">
<text>起领年度(年初)</text>
<text>止领年度(年末)</text>
<text class="withdrawNumber">年提取金额(元)</text>
</view>
<view class="tableTd" v-for="(item,idx) in yearWithdrawalInfos">
<input class="uni-input" type="number" placeholder="请输入"
v-model="item.withdrawalStart"/>
<input class="uni-input" type="number" placeholder="请输入"
v-model="item.withdrawalEnd"/>
<input class="uni-input withdrawNumber" type="digit" placeholder="请输入" maxlength="17"
v-model="item.yearWithdrawalAmount"/>
<view v-show="yearWithdrawalInfos.length>1">
<text @click="reduce(idx)"><svg t="1662455801913" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3447" width="20" height="20"><path d="M512 0c-285.257143 0-512 226.742857-512 512s226.742857 512 512 512 512-226.742857 512-512-226.742857-512-512-512z m0 950.857143c-241.371429 0-438.857143-197.485714-438.857143-438.857143s197.485714-438.857143 438.857143-438.857143 438.857143 197.485714 438.857143 438.857143-197.485714 438.857143-438.857143 438.857143z" p-id="3448" fill="#CEB07D"></path><path d="M731.428571 475.428571h-438.857142c-21.942857 0-36.571429 14.628571-36.571429 36.571429s14.628571 36.571429 36.571429 36.571429h438.857142c21.942857 0 36.571429-14.628571 36.571429-36.571429s-14.628571-36.571429-36.571429-36.571429z" p-id="3449" fill="#CEB07D"></path></svg></text>
</view>
</view>
<text @click="add()" style="position: absolute;right: 0;">
<svg t="1662455996735" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4399" width="20" height="20"><path d="M512 0c-285.257143 0-512 226.742857-512 512s226.742857 512 512 512 512-226.742857 512-512-226.742857-512-512-512z m0 950.857143c-241.371429 0-438.857143-197.485714-438.857143-438.857143s197.485714-438.857143 438.857143-438.857143 438.857143 197.485714 438.857143 438.857143-197.485714 438.857143-438.857143 438.857143z" p-id="4400" fill="#CEB07D"></path><path d="M731.428571 475.428571h-182.857142v-182.857142c0-21.942857-14.628571-36.571429-36.571429-36.571429s-36.571429 14.628571-36.571429 36.571429v182.857142h-182.857142c-21.942857 0-36.571429 14.628571-36.571429 36.571429s14.628571 36.571429 36.571429 36.571429h182.857142v182.857142c0 21.942857 14.628571 36.571429 36.571429 36.571429s36.571429-14.628571 36.571429-36.571429v-182.857142h182.857142c21.942857 0 36.571429-14.628571 36.571429-36.571429s-14.628571-36.571429-36.571429-36.571429z" p-id="4401" fill="#CEB07D"></path></svg>
</text>
</view>
</view>
<!-- 现金价值信息 -->
<view class="cashValueContent" :style="{marginTop:(calcuteType=='1'?'80rpx':'40rpx')}">
<view class="title">
<text>现金价值</text>
<view class="calcTypeOption">
<button class="mini-btn" type="default" size="mini" @click="initCashValue('1')" :class="{'actived':calcuteMethod=='1'}">单次</button>
<button class="mini-btn" type="default" size="mini" @click="initCashValue('2')" :class="{'actived':calcuteMethod=='2'}">批量</button>
</view>
</view>
<view class="simpleCalculateContent" v-show="calcuteMethod==='1'">
<view class="inputItem">
<text>第:</text>
<view class="inputContent">
<input class="uni-input" type="number" placeholder="请输入" min='1' maxlength="3"
v-model="irrAndSimple.nyear"/>
<label for=""></label>
</view>
</view>
<view class="inputItem">
<text>{{irrAndSimpleCalcuteParam.allFirstPayment > 0 ? '总生存利益(现金价值+万能账户现价)' :'现金价值'}}:</text>
<view class="inputContent">
<input class="uni-input" type="digit" placeholder="请输入" min='1' maxlength="17"
v-model="irrAndSimple.cashValue"/>
<label for=""></label>
</view>
</view>
</view>
<view class="batchCalculateContent" v-show="!resultShowFlag && calcuteMethod==='2'">
<img src="/static/images/batchFileImport.png" alt="" style="width: 50%;">
<text>暂无数据</text>
<text style="font-size: 14px;margin-top: 10rpx;">点击下方按钮输入批量数据</text>
</view>
</view>
<!-- 现金价值单利复利结果展示 -->
<view class="resultContent" id="resultContent">
<!-- 单次计算显示结果 -->
<view id="simpleDataResult" class="simpleDataResult" v-if="resultShowFlag && calcuteMethod == '1'">
<view class="inputItem">
<text class="resultTitle">IRR复利</text>
<text class="calcNumber">{{irrAndSimpleResInfos.length>0?(irrAndSimpleResInfos[0]['irrValue'] * 100).toFixed(3):null}}%</text>
</view>
<view class="inputItem">
<text class="resultTitle">单利</text>
<text class="calcNumber">{{irrAndSimpleResInfos.length>0?(irrAndSimpleResInfos[0]['simpleValue'] * 100).toFixed(3):null}}%</text>
</view>
</view>
<!-- 批量计算显示结果 -->
<view class="batchDataResult" v-if="resultShowFlag && calcuteMethod == '2'">
<scroll-view scroll-y="true" class="scroll-Y">
<view class="scroll-view-item">
<view class="resultTh">
<text>保单年度</text>
<text>现金价值</text>
<text>IRR复利</text>
<text>单利</text>
</view>
<view class="resultTd" v-for="item in resIrrAndSimpleResInfos">
<text>{{item.nyear}}</text>
<text>{{numberConverter(item.cashValue)}}</text>
<text class="resultNumber">{{(item.irrValue*100).toFixed(3)}}%</text>
<text class="resultNumber">{{(item.simpleValue * 100).toFixed(3)}}%</text>
</view>
</view>
</scroll-view>
</view>
</view>
<foot></foot>
<!-- 操作 -->
<view class="optionContent">
<button type="default" plain="true" form-type="reset"
@click="resetData()">清空</button>
<button type="default" plain="true"
class="sfp_btn" @click="calcute(2)"
v-show="calcuteMethod==2">输入批量数据</button>
<button type="default" plain="true" class="sfp_btn"
@click="calcute(1)" v-show="calcuteMethod==1"
>开始计算</button>
</view>
</form>
</scroll-view>
</view>
</template>
<script>
import api from "../../api/api";
import {nanoid} from 'nanoid';
import dataHandling from "../../util/dataHandling";
import dataImport from "../dataImport/data-import.vue";
import { inject } from "vue";
import foot from '../footer/footer.vue';
import { toRefs, ref } from 'vue';
import commonHead from '../header/header.vue';
export default {
data() {
return {
calcuteType:'1', //计算类型(1:增额; 2:年金)
withdrawalType:'1', //提领方式(1:正常提领; 2:减保取现)
resultShowFlag:false,
calcuteMethod:'1', //计算方式(1:单次; 2:批量)
businessType:1, //业务类型(1:计算; 2:保存)
mobile:undefined,
irrAndSimpleCalcuteParam:{},
yearWithdrawal:{
withdrawalType:undefined,
withdrawalStart:undefined,
withdrawalEnd:undefined,
yearWithdrawalAmount:undefined,
},
irrAndSimple:{
nyear:undefined,
cashValue:undefined
},
yearWithdrawalInfos:[],
irrAndSimpleInfos:[],
irrAndSimpleResInfos:[] ,// 计算结果
resIrrAndSimpleResInfos:[],
irrFlag:Boolean = false,
}
},
components:{
dataImport,
foot,
commonHead
},
onLoad() {
if(dataHandling.getQueryString('isBack') == 1){
const calcuteData = uni.getStorageSync('calcuteData') ? JSON.parse(uni.getStorageSync('calcuteData')) : null;
if(calcuteData){
this.irrAndSimpleCalcuteParam.paymentPeriod = calcuteData.paymentPeriod;
this.irrAndSimpleCalcuteParam.annualPremium = calcuteData.annualPremium;
this.irrAndSimpleCalcuteParam.allFirstPayment = calcuteData.allFirstPayment;
this.businessType = calcuteData.businessType;
this.calcuteType = calcuteData.calcuteType;
this.yearWithdrawalInfos = calcuteData.yearWithdrawalInfos;
this.withdrawalType = calcuteData.withdrawalType;
}
}else{
//初始化删除上次批量计算结果
uni.removeStorageSync('resIrrAndSimpleResInfos');
}
if(this.yearWithdrawal.length>0){
this.yearWithdrawalInfos.push({...this.yearWithdrawal,withdrawalType:this.withdrawalType?'1':'2'})
}
},
methods: {
checkToken(){
api.checkToken().then(res=>{
if(res['success']){}else{
api.obtainToken().then(res=>{
if(res.success){
uni.setStorageSync('uni-token',res.data['token']);
}
})
}
})
},
getFollowData(e){
this.isNeedOfficialAccountQrcode= ref(e);
console.log('父组件拿到值了',e);
},
// 使用说明跳转
instructionForUse(){
window.location.href = 'https://mp.weixin.qq.com/s/ZmlFZv51Pr0qpKeFiebI3Q';
},
// 数字千分位处理
numberConverter(val){
return dataHandling.numberConverter(val)
},
// 封装报错弹窗
errorDialog(type,content){
// type 1 必填项校验 2 规则校验
uni.showModal({
title: type===1 ? '必填项校验' : '规则校验',
content:content,
showCancel:false,
success: function (res) {
if (res.confirm) {
console.log('用户点击确定');
} else if (res.cancel) {
console.log('用户点击取消');
}
}
});
},
// 当有万能账户时,提领信息清空
withdrawalTypeInit(){
if(this.irrAndSimpleCalcuteParam.allFirstPayment>0) {
this.yearWithdrawalInfos=null
}else{
this.yearWithdrawalInfos = [].concat([{withdrawalType:'1',
withdrawalStart:null,
yearWithdrawalAmount:null}]);
}
},
switchTab(e){
if(this.calcuteType !=e){
this.calcuteType = e;
//点年金时初始化1条提领信息
if(e=='2'){
this.irrAndSimpleCalcuteParam.allFirstPayment = null;
this.yearWithdrawalInfos = [].concat([{withdrawalType:'1',
withdrawalStart:null,
yearWithdrawalAmount:null}]);
}else if(e=='1'){
this.irrAndSimpleCalcuteParam.allFirstPayment = null;
if(this.withdrawalType == '1'){
this.yearWithdrawalInfos = [];
}else{
this.yearWithdrawalInfos = [].concat([{withdrawalType:'2',
withdrawalStart:null,
yearWithdrawalAmount:null,
withdrawalEnd:null}]);
}
}
this.resultShowFlag = false;
}
},
// calcuteMethod判断单次还是批量;businessType判断保存还是计算
calcute(businessType){
if(this.calcuteMethod==='1'){
// 计算
this.irrAndSimpleCalte();
}else if(this.calcuteMethod === '2'){
//批量
if(!this.irrAndSimpleCalcuteParam.paymentPeriod || this.irrAndSimpleCalcuteParam.paymentPeriod==0){
this.errorDialog(1,`交费年限为必填项且必须大于0`);
return false;
}
if(!this.irrAndSimpleCalcuteParam.annualPremium){
this.errorDialog(1,`年交保费为必填项`);
return false;
}
//提领信息判断
if(this.yearWithdrawalInfos && this.yearWithdrawalInfos.length>0){
for (let i = 0; i < this.yearWithdrawalInfos.length; i++) {
//增额提领信息校验
if(this.calcuteType == 1){
if(!this.yearWithdrawalInfos[i].withdrawalStart || !this.yearWithdrawalInfos[i].withdrawalEnd || this.yearWithdrawalInfos[i].withdrawalStart<=0 || this.yearWithdrawalInfos[i].withdrawalEnd<=0){
this.errorDialog(1,`请输入第${i+1}行提领起领年度和止领年度,且该保单年度必须大于0`);
return false;
}else{
if(Number(this.yearWithdrawalInfos[i].withdrawalStart) > Number(this.yearWithdrawalInfos[i].withdrawalEnd)){
this.errorDialog(2,`第${i+1}行,起领年度必须小于等于止领年度!`);
return false;
}
}
if(this.yearWithdrawalInfos[i]['yearWithdrawalAmount'] && this.yearWithdrawalInfos[i]['yearWithdrawalAmount']<=0){
this.errorDialog(2,`第${i+1}行,提领金额必须大于0`);
return false;
}else if(Number(this.yearWithdrawalInfos[i]['yearWithdrawalAmount']) > 999999999999999){
this.errorDialog(2,`第${i+1}行,提领金额必须小于999,999,999,999,999`);
return false;
}else{
if(!this.yearWithdrawalInfos[i]['yearWithdrawalAmount']){
this.errorDialog(1,`请输入第${i+1}行,提领金额`);
return false;
}
}
}
//年金提领信息校验
if(this.calcuteType == '2'){
if(!this.yearWithdrawalInfos[i]['withdrawalStart'] || this.yearWithdrawalInfos[i]['withdrawalStart']<0){
this.errorDialog(1,`请输入提领信息保单年度,且年度值必须大于0`);
return false;
}
if(!this.yearWithdrawalInfos[i]['yearWithdrawalAmount']){
this.errorDialog(1,'请输入提领金额');
return false;
}else{
if(this.yearWithdrawalInfos[i]['yearWithdrawalAmount']<0){
this.errorDialog(1,'提领金额必须大于等于0');
return false;
}
if(Number(this.yearWithdrawalInfos[i]['yearWithdrawalAmount']>999999999999999)){
this.errorDialog(1,'提领金额必须小于999,999,999,999,999');
return false;
}
}
}
}
}
// 输入批量数据,缓存当页数据
const calcuteData = {
paymentPeriod:this.irrAndSimpleCalcuteParam.paymentPeriod,
annualPremium:this.irrAndSimpleCalcuteParam.annualPremium,
allFirstPayment:this.irrAndSimpleCalcuteParam.allFirstPayment,
yearWithdrawalInfos:this.yearWithdrawalInfos,
calcuteType:this.calcuteType,
businessNo:nanoid(),
businessType:this.businessType,
withdrawalType:this.withdrawalType,
systemType:1,
userId:uni.getStorageSync('cffp_userId')
}
uni.setStorageSync('calcuteData',JSON.stringify(calcuteData))
uni.navigateTo({
url: `/sfp/dataImport/data-import?isUniversalAccount=${this.irrAndSimpleCalcuteParam.allFirstPayment > 0 ? '1' : '0'}`
});
// this.irrFlag = true;
}
},
//点击单次时初始化数据
initCashValue(calcuteMethod){
if(this.calcuteMethod != calcuteMethod){
this.calcuteMethod = calcuteMethod;
if(calcuteMethod === '1'){
this.irrAndSimple = {nyear:null,cashValue:null};
this.irrAndSimpleInfos = [].concat([{nyear:null,cashValue:null}]);
}
//切换单次还是批量时,清空结果
this.resultShowFlag = false;
}
},
changeWithdrawalType(){
this.withdrawalType = !this.withdrawalType;
if(!this.withdrawalType){
this.yearWithdrawalInfos = [].concat([{withdrawalType:'2',
withdrawalStart:null,
withdrawalEnd:null,
yearWithdrawalAmount:null,}]);
console.log(this.yearWithdrawalInfos)
}else{
this.yearWithdrawalInfos = [];
}
},
//提领信息+
add(){
this.yearWithdrawalInfos.push({
withdrawalType:undefined,
withdrawalStart:undefined,
withdrawalEnd:undefined,
yearWithdrawalAmount:undefined,
withdrawalType:this.withdrawalType?'1':'2'
})
},
//提领信息-
reduce(idx){
if(this.yearWithdrawalInfos.length>1){
this.yearWithdrawalInfos.splice(idx,1)
}
},
// 计算接口
irrAndSimpleCalte(){
if(!this.irrAndSimpleCalcuteParam.paymentPeriod || this.irrAndSimpleCalcuteParam.paymentPeriod <= 0){
this.errorDialog(1,`交费年限为必填项且必须大于0`);
return false;
}else{
if(this.irrAndSimpleCalcuteParam.paymentPeriod >50 ){
this.errorDialog(2,`交费年限一般不大于50年,请确认!`);
return false;
}
}
if(!this.irrAndSimpleCalcuteParam.annualPremium){
this.errorDialog(1,`年交保费为必填项!`);
return false;
}else{
if(this.irrAndSimpleCalcuteParam.annualPremium > 999999999999999){
this.errorDialog(2,`年交保费不能大于999,999,999,999,999!`);
return false;
}
if(this.irrAndSimpleCalcuteParam.annualPremium <= 0){
this.errorDialog(2,`年交保费必须大于0!`);
return false;
}
}
if(this.irrAndSimpleCalcuteParam.allFirstPayment && this.irrAndSimpleCalcuteParam.allFirstPayment < 0){
this.errorDialog(2,`万能账户首年交费须大于或等于0!`);
return false;
}
if(this.irrAndSimpleCalcuteParam.allFirstPayment && this.irrAndSimpleCalcuteParam.allFirstPayment > 999999999999999){
this.errorDialog(2,`万能账户首年交费必须小于999,999,999,999,999!`);
return false;
}
if(this.businessType == 2){
if(!this.mobile){
this.errorDialog(1,`保存时手机号必填!`);
return false;
}
}
//提领信息判断
if(this.yearWithdrawalInfos && this.yearWithdrawalInfos.length>0){
for (let i = 0; i < this.yearWithdrawalInfos.length; i++) {
//增额提领信息校验
if(this.calcuteType == 1){
if(!this.yearWithdrawalInfos[i].withdrawalStart || !this.yearWithdrawalInfos[i].withdrawalEnd || this.yearWithdrawalInfos[i].withdrawalStart<=0 || this.yearWithdrawalInfos[i].withdrawalEnd<=0){
this.errorDialog(1,`请输入第${i+1}行提领起领年度和止领年度,且该保单年度必须大于0`);
return false;
}else{
if(Number(this.yearWithdrawalInfos[i].withdrawalStart) > Number(this.yearWithdrawalInfos[i].withdrawalEnd)){
this.errorDialog(2,`第${i+1}行,起领年度必须小于等于止领年度!`);
return false;
}
}
if(this.yearWithdrawalInfos[i]['yearWithdrawalAmount'] && this.yearWithdrawalInfos[i]['yearWithdrawalAmount']<=0){
this.errorDialog(2,`第${i+1}行,提领金额必须大于0`);
return false;
}else if(Number(this.yearWithdrawalInfos[i]['yearWithdrawalAmount']) > 999999999999999){
this.errorDialog(2,`第${i+1}行,提领金额必须小于999,999,999,999,999`);
return false;
}else{
if(!this.yearWithdrawalInfos[i]['yearWithdrawalAmount']){
this.errorDialog(1,`请输入第${i+1}行,提领金额`);
return false;
}
}
}
//年金提领信息校验
if(this.calcuteType == '2'){
if(!this.yearWithdrawalInfos[i]['withdrawalStart'] || this.yearWithdrawalInfos[i]['withdrawalStart']<0){
this.errorDialog(1,`请输入提领信息保单年度,且年度值必须大于0`);
return false;
}
if(!this.yearWithdrawalInfos[i]['yearWithdrawalAmount']){
this.errorDialog(1,'请输入提领金额');
return false;
}else{
if(this.yearWithdrawalInfos[i]['yearWithdrawalAmount']<0){
this.errorDialog(1,'提领金额必须大于等于0');
return false;
}
if(Number(this.yearWithdrawalInfos[i]['yearWithdrawalAmount']>999999999999999)){
this.errorDialog(1,'提领金额必须小于999,999,999,999,999');
return false;
}
}
}
}
}
if(this.calcuteMethod == 1){
if(!this.irrAndSimple.nyear && this.irrAndSimple.nyear!=0){
this.errorDialog(1,`请输入现金价值年度!`);
return false;
}else{
if(Number(this.irrAndSimple.nyear)>105){
this.errorDialog(2,`现金价值年度不能大于105!`);
return false;
}
if(this.irrAndSimple.nyear<=0){
this.errorDialog(2,`现金价值年度必须大于0!`);
return false;
}
}
if(!this.irrAndSimple.cashValue || this.irrAndSimple.cashValue<0){
this.errorDialog(1,'请输入现金价值且现金价值只能大于或等于0!');
return false;
}else{
if(Number(this.irrAndSimple.cashValue) > 999999999999999){
this.errorDialog(1,'现金价值必须小于999,999,999,999,999');
return false;
}
}
}
const params = {
...this.irrAndSimpleCalcuteParam,
calcuteType:this.calcuteType,
businessType:this.businessType,
calcuteMethod:this.calcuteMethod,
businessNo:nanoid(),
mobile: null,
loginNo: null,
wechat_openid: uni.getStorageSync('openId') || '',
yearWithdrawalInfos:this.yearWithdrawalInfos,
irrAndSimpleInfos:[].concat([this.irrAndSimple]),
withdrawalType:this.withdrawalType?'1':'2',
decimal: 5,
systemType:1,
userId:uni.getStorageSync('cffp_userId')
};
api.irrAndSimpleCalcute(params).then(res=>{
if(res.success === true){
// 出结果之后自动滑倒底部
setTimeout(()=>{
uni.pageScrollTo({
duration:100,
scrollTop:200000
})
},100)
if(res.data.irrAndSimpleResInfos){
this.irrAndSimpleResInfos = res.data.irrAndSimpleResInfos;
this.resultShowFlag = true;
}else{
this.irrAndSimpleResInfos = [];
}
}else{
if(res.data.calcuteCode=='0'){
// 没有关注公众号
this.isNeedOfficialAccountQrcode = true;
return false;
}
this.irrAndSimpleResInfos = [];
uni.showToast({
title: res['message'],
duration: 2000,
icon: 'none'
})
}
})
},
resetData(){
this.irrAndSimpleCalcuteParam = {};
this.yearWithdrawalInfos = [];
this.withdrawalType = '1';
this.irrAndSimple = {nyear:undefined,cashValue:undefined};
this.resultShowFlag = false;
}
},
onShow() {
if(uni.getStorageSync('resIrrAndSimpleResInfos')){
this.resIrrAndSimpleResInfos = uni.getStorageSync('resIrrAndSimpleResInfos');
this.calcuteMethod = '2';
this.resultShowFlag = true;
}
},
mounted() {
this.checkToken();
}
}
</script>
<style>
@import '../sfpCommon.css';
@import 'index.css';
</style>
.banner{
width: 100%;
position: relative;
}
.banner > text{
position: absolute;
bottom: 40px;
left: 0;
color: #fff;
background: rgba(0,0,0,0.35);
padding: 2px 10px;
border-top-right-radius: 20px;
border-bottom-right-radius: 20px;
}
.banner img{
width: 100%;
}
.formInfoContainer{
background: #fff;
margin-top: -32rpx;
position: relative;
z-index: 2;
border-top-right-radius: 30rpx;
border-top-left-radius: 30rpx;
padding: 30rpx;
box-sizing: border-box;
font-size: 30rpx;
color: #333333;
scroll-behavior:smooth;
}
.title{
display: flex;
justify-content: space-between;
align-items: center;
color: #CEB07D;
font-weight: bold;
font-size: 32rpx;
position: relative;
padding-left: 28rpx;
margin: 20rpx 0;
height: 50rpx;
}
.title::before{
content: '';
position: absolute;
left: 0;
top: 15rpx;
width: 6rpx;
height: 20rpx;
background-color: #CEB07D;
border-radius: 8rpx;
}
.radioButton{
position: relative;
width: 40rpx;
height: 40rpx;
border-radius: 50%;
border: 1px solid #CEB07D;
}
.radioButton.selected::after{
content: '';
position: absolute;
left: 0;
top: 0;
width: 20rpx;
height: 20rpx;
transform: translate(10rpx,10rpx);
border-radius: 50%;
background: linear-gradient(135deg, #CEB07D 0%, #FFDDA9 56%, #FED495 100%, #FED495 100%);
}
.inputItem{
display: flex;
justify-content: space-between;
align-items: center;
height: 80rpx;
border-bottom: 1px solid #E4E4E4;
}
.inputItem .inputContent{
display: flex;
align-items: center;
justify-content: flex-end;
flex: 0 0 40%;
}
.inputContent .uni-input{
margin-right: 20rpx;
text-align: right;
}
.inputItem text{
flex: 0 0 60%;
}
.uni-input-placeholder{
color: #999999;
font-size: 24rpx;
}
.optionContent{
position: fixed;
bottom: 0;
left: 0;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
background-color: #fff;
padding-bottom: 30rpx;
z-index: 1;
}
.optionContent button{
flex: 0 0 46%;
border:2rpx solid #e7c793!important;
font-size: 36rpx;
}
.sfp_btn{
background: linear-gradient(135deg, #CEB07D 0%, #FFDDA9 56%, #FED495 100%, #FED495 100%);
border: none;
color: #6B4000;
}
\ No newline at end of file
## 1.0.1(2021-11-23)
- 优化 label、label-width 属性
## 1.0.0(2021-11-19)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-combox](https://uniapp.dcloud.io/component/uniui/uni-combox)
## 0.1.0(2021-07-30)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.0.6(2021-05-12)
- 新增 组件示例地址
## 0.0.5(2021-04-21)
- 优化 添加依赖 uni-icons, 导入后自动下载依赖
## 0.0.4(2021-02-05)
- 优化 组件引用关系,通过uni_modules引用组件
## 0.0.3(2021-02-04)
- 调整为uni_modules目录规范
<template>
<view class="uni-combox" :class="border ? '' : 'uni-combox__no-border'">
<view v-if="label" class="uni-combox__label" :style="labelStyle">
<text>{{label}}</text>
</view>
<view class="uni-combox__input-box">
<input class="uni-combox__input" type="text" :placeholder="placeholder"
placeholder-class="uni-combox__input-plac" v-model="inputVal" @input="onInput" @focus="onFocus"
@blur="onBlur" />
<uni-icons :type="showSelector? 'top' : 'bottom'" size="14" color="#999" @click="toggleSelector">
</uni-icons>
</view>
<view class="uni-combox__selector" v-if="showSelector">
<view class="uni-popper__arrow"></view>
<scroll-view scroll-y="true" class="uni-combox__selector-scroll">
<view class="uni-combox__selector-empty" v-if="filterCandidatesLength === 0">
<text>{{emptyTips}}</text>
</view>
<view class="uni-combox__selector-item" v-for="(item,index) in filterCandidates" :key="index"
@click="onSelectorClick(index)">
<text>{{item}}</text>
</view>
</scroll-view>
</view>
</view>
</template>
<script>
/**
* Combox 组合输入框
* @description 组合输入框一般用于既可以输入也可以选择的场景
* @tutorial https://ext.dcloud.net.cn/plugin?id=1261
* @property {String} label 左侧文字
* @property {String} labelWidth 左侧内容宽度
* @property {String} placeholder 输入框占位符
* @property {Array} candidates 候选项列表
* @property {String} emptyTips 筛选结果为空时显示的文字
* @property {String} value 组合框的值
*/
export default {
name: 'uniCombox',
emits: ['input', 'update:modelValue'],
props: {
border: {
type: Boolean,
default: true
},
label: {
type: String,
default: ''
},
labelWidth: {
type: String,
default: 'auto'
},
placeholder: {
type: String,
default: ''
},
candidates: {
type: Array,
default () {
return []
}
},
emptyTips: {
type: String,
default: '无匹配项'
},
// #ifndef VUE3
value: {
type: [String, Number],
default: ''
},
// #endif
// #ifdef VUE3
modelValue: {
type: [String, Number],
default: ''
},
// #endif
},
data() {
return {
showSelector: false,
inputVal: ''
}
},
computed: {
labelStyle() {
if (this.labelWidth === 'auto') {
return ""
}
return `width: ${this.labelWidth}`
},
filterCandidates() {
return this.candidates.filter((item) => {
return item.toString().indexOf(this.inputVal) > -1
})
},
filterCandidatesLength() {
return this.filterCandidates.length
}
},
watch: {
// #ifndef VUE3
value: {
handler(newVal) {
this.inputVal = newVal
},
immediate: true
},
// #endif
// #ifdef VUE3
modelValue: {
handler(newVal) {
this.inputVal = newVal
},
immediate: true
},
// #endif
},
methods: {
toggleSelector() {
this.showSelector = !this.showSelector
},
onFocus() {
this.showSelector = true
},
onBlur() {
setTimeout(() => {
this.showSelector = false
}, 153)
},
onSelectorClick(index) {
this.inputVal = this.filterCandidates[index]
this.showSelector = false
this.$emit('input', this.inputVal)
this.$emit('update:modelValue', this.inputVal)
},
onInput() {
setTimeout(() => {
this.$emit('input', this.inputVal)
this.$emit('update:modelValue', this.inputVal)
})
}
}
}
</script>
<style lang="scss" scoped>
.uni-combox {
font-size: 14px;
border: 1px solid #DCDFE6;
border-radius: 4px;
padding: 6px 10px;
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
// height: 40px;
flex-direction: row;
align-items: center;
// border-bottom: solid 1px #DDDDDD;
}
.uni-combox__label {
font-size: 16px;
line-height: 22px;
padding-right: 10px;
color: #999999;
}
.uni-combox__input-box {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex: 1;
flex-direction: row;
align-items: center;
}
.uni-combox__input {
flex: 1;
font-size: 14px;
height: 22px;
line-height: 22px;
}
.uni-combox__input-plac {
font-size: 14px;
color: #999;
}
.uni-combox__selector {
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
position: absolute;
top: calc(100% + 12px);
left: 0;
width: 100%;
background-color: #FFFFFF;
border: 1px solid #EBEEF5;
border-radius: 6px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
z-index: 2;
padding: 4px 0;
}
.uni-combox__selector-scroll {
/* #ifndef APP-NVUE */
max-height: 200px;
box-sizing: border-box;
/* #endif */
}
.uni-combox__selector-empty,
.uni-combox__selector-item {
/* #ifndef APP-NVUE */
display: flex;
cursor: pointer;
/* #endif */
line-height: 36px;
font-size: 14px;
text-align: center;
// border-bottom: solid 1px #DDDDDD;
padding: 0px 10px;
}
.uni-combox__selector-item:hover {
background-color: #f9f9f9;
}
.uni-combox__selector-empty:last-child,
.uni-combox__selector-item:last-child {
/* #ifndef APP-NVUE */
border-bottom: none;
/* #endif */
}
// picker 弹出层通用的指示小三角
.uni-popper__arrow,
.uni-popper__arrow::after {
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
}
.uni-popper__arrow {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
top: -6px;
left: 10%;
margin-right: 3px;
border-top-width: 0;
border-bottom-color: #EBEEF5;
}
.uni-popper__arrow::after {
content: " ";
top: 1px;
margin-left: -6px;
border-top-width: 0;
border-bottom-color: #fff;
}
.uni-combox__no-border {
border: none;
}
</style>
{
"id": "uni-combox",
"displayName": "uni-combox 组合框",
"version": "1.0.1",
"description": "可以选择也可以输入的表单项 ",
"keywords": [
"uni-ui",
"uniui",
"combox",
"组合框",
"select"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": [
"uni-scss",
"uni-icons"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "n"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}
\ No newline at end of file
## Combox 组合框
> **组件名:uni-combox**
> 代码块: `uCombox`
组合框组件。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-combox)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
## 1.0.8(2022-09-16)
- 可以使用 uni-scss 控制主题色
## 1.0.7(2022-07-06)
- 优化 pc端图标位置不正确的问题
## 1.0.6(2022-07-05)
- 优化 显示样式
## 1.0.5(2022-07-04)
- 修复 uni-data-picker 在 uni-forms-item 中宽度不正确的bug
## 1.0.4(2022-04-19)
- 修复 字节小程序 本地数据无法选择下一级的Bug
## 1.0.3(2022-02-25)
- 修复 nvue 不支持的 v-show 的 bug
## 1.0.2(2022-02-25)
- 修复 条件编译 nvue 不支持的 css 样式
## 1.0.1(2021-11-23)
- 修复 由上个版本引发的map、v-model等属性不生效的bug
## 1.0.0(2021-11-19)
- 优化 组件 UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-data-picker](https://uniapp.dcloud.io/component/uniui/uni-data-picker)
## 0.4.9(2021-10-28)
- 修复 VUE2 v-model 概率无效的 bug
## 0.4.8(2021-10-27)
- 修复 v-model 概率无效的 bug
## 0.4.7(2021-10-25)
- 新增 属性 spaceInfo 服务空间配置 HBuilderX 3.2.11+
- 修复 树型 uniCloud 数据类型为 int 时报错的 bug
## 0.4.6(2021-10-19)
- 修复 非 VUE3 v-model 为 0 时无法选中的 bug
## 0.4.5(2021-09-26)
- 新增 清除已选项的功能(通过 clearIcon 属性配置是否显示按钮),同时提供 clear 方法以供调用,二者等效
- 修复 readonly 为 true 时报错的 bug
## 0.4.4(2021-09-26)
- 修复 上一版本造成的 map 属性失效的 bug
- 新增 ellipsis 属性,支持配置 tab 选项长度过长时是否自动省略
## 0.4.3(2021-09-24)
- 修复 某些情况下级联未触发的 bug
## 0.4.2(2021-09-23)
- 新增 提供 show 和 hide 方法,开发者可以通过 ref 调用
- 新增 选项内容过长自动添加省略号
## 0.4.1(2021-09-15)
- 新增 map 属性 字段映射,将 text/value 映射到数据中的其他字段
## 0.4.0(2021-07-13)
- 组件兼容 vue3,如何创建 vue3 项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 0.3.5(2021-06-04)
- 修复 无法加载云端数据的问题
## 0.3.4(2021-05-28)
- 修复 v-model 无效问题
- 修复 loaddata 为空数据组时加载时间过长问题
- 修复 上个版本引出的本地数据无法选择带有 children 的 2 级节点
## 0.3.3(2021-05-12)
- 新增 组件示例地址
## 0.3.2(2021-04-22)
- 修复 非树形数据有 where 属性查询报错的问题
## 0.3.1(2021-04-15)
- 修复 本地数据概率无法回显时问题
## 0.3.0(2021-04-07)
- 新增 支持云端非树形表结构数据
- 修复 根节点 parent_field 字段等于 null 时选择界面错乱问题
## 0.2.0(2021-03-15)
- 修复 nodeclick、popupopened、popupclosed 事件无法触发的问题
## 0.1.9(2021-03-09)
- 修复 微信小程序某些情况下无法选择的问题
## 0.1.8(2021-02-05)
- 优化 部分样式在 nvue 上的兼容表现
## 0.1.7(2021-02-05)
- 调整为 uni_modules 目录规范
// #ifdef H5
export default {
name: 'Keypress',
props: {
disable: {
type: Boolean,
default: false
}
},
mounted () {
const keyNames = {
esc: ['Esc', 'Escape'],
tab: 'Tab',
enter: 'Enter',
space: [' ', 'Spacebar'],
up: ['Up', 'ArrowUp'],
left: ['Left', 'ArrowLeft'],
right: ['Right', 'ArrowRight'],
down: ['Down', 'ArrowDown'],
delete: ['Backspace', 'Delete', 'Del']
}
const listener = ($event) => {
if (this.disable) {
return
}
const keyName = Object.keys(keyNames).find(key => {
const keyName = $event.key
const value = keyNames[key]
return value === keyName || (Array.isArray(value) && value.includes(keyName))
})
if (keyName) {
// 避免和其他按键事件冲突
setTimeout(() => {
this.$emit(keyName, {})
}, 0)
}
}
document.addEventListener('keyup', listener)
this.$once('hook:beforeDestroy', () => {
document.removeEventListener('keyup', listener)
})
},
render: () => {}
}
// #endif
<template>
<view class="uni-data-tree">
<view class="uni-data-tree-input" @click="handleInput">
<slot :options="options" :data="inputSelected" :error="errorMessage">
<view class="input-value" :class="{'input-value-border': border}">
<text v-if="errorMessage" class="selected-area error-text">{{errorMessage}}</text>
<view v-else-if="loading && !isOpened" class="selected-area">
<uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
</view>
<scroll-view v-else-if="inputSelected.length" class="selected-area" scroll-x="true">
<view class="selected-list">
<view class="selected-item" v-for="(item,index) in inputSelected" :key="index">
<text class="text-color">{{item.text}}</text><text v-if="index<inputSelected.length-1"
class="input-split-line">{{split}}</text>
</view>
</view>
</scroll-view>
<text v-else class="selected-area placeholder">{{placeholder}}</text>
<view v-if="clearIcon && !readonly && inputSelected.length" class="icon-clear"
@click.stop="clear">
<uni-icons type="clear" color="#c0c4cc" size="24"></uni-icons>
</view>
<view class="arrow-area" v-if="(!clearIcon || !inputSelected.length) && !readonly ">
<view class="input-arrow"></view>
</view>
</view>
</slot>
</view>
<view class="uni-data-tree-cover" v-if="isOpened" @click="handleClose"></view>
<view class="uni-data-tree-dialog" v-if="isOpened">
<view class="uni-popper__arrow"></view>
<view class="dialog-caption">
<view class="title-area">
<text class="dialog-title">{{popupTitle}}</text>
</view>
<view class="dialog-close" @click="handleClose">
<view class="dialog-close-plus" data-id="close"></view>
<view class="dialog-close-plus dialog-close-rotate" data-id="close"></view>
</view>
</view>
<data-picker-view class="picker-view" ref="pickerView" v-model="dataValue" :localdata="localdata"
:preload="preload" :collection="collection" :field="field" :orderby="orderby" :where="where"
:step-searh="stepSearh" :self-field="selfField" :parent-field="parentField" :managed-mode="true"
:map="map" :ellipsis="ellipsis" @change="onchange" @datachange="ondatachange" @nodeclick="onnodeclick">
</data-picker-view>
</view>
</view>
</template>
<script>
import dataPicker from "../uni-data-pickerview/uni-data-picker.js"
import DataPickerView from "../uni-data-pickerview/uni-data-pickerview.vue"
/**
* DataPicker 级联选择
* @description 支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。
* @tutorial https://ext.dcloud.net.cn/plugin?id=3796
* @property {String} popup-title 弹出窗口标题
* @property {Array} localdata 本地数据,参考
* @property {Boolean} border = [true|false] 是否有边框
* @property {Boolean} readonly = [true|false] 是否仅读
* @property {Boolean} preload = [true|false] 是否预加载数据
* @value true 开启预加载数据,点击弹出窗口后显示已加载数据
* @value false 关闭预加载数据,点击弹出窗口后开始加载数据
* @property {Boolean} step-searh = [true|false] 是否分布查询
* @value true 启用分布查询,仅查询当前选中节点
* @value false 关闭分布查询,一次查询出所有数据
* @property {String|DBFieldString} self-field 分布查询当前字段名称
* @property {String|DBFieldString} parent-field 分布查询父字段名称
* @property {String|DBCollectionString} collection 表名
* @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
* @property {String} orderby 排序字段及正序倒叙设置
* @property {String|JQLString} where 查询条件
* @event {Function} popupshow 弹出的选择窗口打开时触发此事件
* @event {Function} popuphide 弹出的选择窗口关闭时触发此事件
*/
export default {
name: 'UniDataPicker',
emits: ['popupopened', 'popupclosed', 'nodeclick', 'input', 'change', 'update:modelValue'],
mixins: [dataPicker],
components: {
DataPickerView
},
props: {
options: {
type: [Object, Array],
default () {
return {}
}
},
popupTitle: {
type: String,
default: '请选择'
},
placeholder: {
type: String,
default: '请选择'
},
heightMobile: {
type: String,
default: ''
},
readonly: {
type: Boolean,
default: false
},
clearIcon: {
type: Boolean,
default: true
},
border: {
type: Boolean,
default: true
},
split: {
type: String,
default: '/'
},
ellipsis: {
type: Boolean,
default: true
}
},
data() {
return {
isOpened: false,
inputSelected: []
}
},
created() {
this.form = this.getForm('uniForms')
this.formItem = this.getForm('uniFormsItem')
if (this.formItem) {
if (this.formItem.name) {
this.rename = this.formItem.name
this.form.inputChildrens.push(this)
}
}
this.$nextTick(() => {
this.load()
})
},
methods: {
clear() {
this.inputSelected.splice(0)
this._dispatchEvent([])
},
onPropsChange() {
this._treeData = []
this.selectedIndex = 0
this.load()
},
load() {
if (this.readonly) {
this._processReadonly(this.localdata, this.dataValue)
return
}
if (this.isLocaldata) {
this.loadData()
this.inputSelected = this.selected.slice(0)
} else if (!this.parentField && !this.selfField && this.hasValue) {
this.getNodeData(() => {
this.inputSelected = this.selected.slice(0)
})
} else if (this.hasValue) {
this.getTreePath(() => {
this.inputSelected = this.selected.slice(0)
})
}
},
getForm(name = 'uniForms') {
let parent = this.$parent;
let parentName = parent.$options.name;
while (parentName !== name) {
parent = parent.$parent;
if (!parent) return false;
parentName = parent.$options.name;
}
return parent;
},
show() {
this.isOpened = true
setTimeout(() => {
this.$refs.pickerView.updateData({
treeData: this._treeData,
selected: this.selected,
selectedIndex: this.selectedIndex
})
}, 200)
this.$emit('popupopened')
},
hide() {
this.isOpened = false
this.$emit('popupclosed')
},
handleInput() {
if (this.readonly) {
return
}
this.show()
},
handleClose(e) {
this.hide()
},
onnodeclick(e) {
this.$emit('nodeclick', e)
},
ondatachange(e) {
this._treeData = this.$refs.pickerView._treeData
},
onchange(e) {
this.hide()
this.$nextTick(() => {
this.inputSelected = e;
})
this._dispatchEvent(e)
},
_processReadonly(dataList, value) {
var isTree = dataList.findIndex((item) => {
return item.children
})
if (isTree > -1) {
let inputValue
if (Array.isArray(value)) {
inputValue = value[value.length - 1]
if (typeof inputValue === 'object' && inputValue.value) {
inputValue = inputValue.value
}
} else {
inputValue = value
}
this.inputSelected = this._findNodePath(inputValue, this.localdata)
return
}
if (!this.hasValue) {
this.inputSelected = []
return
}
let result = []
for (let i = 0; i < value.length; i++) {
var val = value[i]
var item = dataList.find((v) => {
return v.value == val
})
if (item) {
result.push(item)
}
}
if (result.length) {
this.inputSelected = result
}
},
_filterForArray(data, valueArray) {
var result = []
for (let i = 0; i < valueArray.length; i++) {
var value = valueArray[i]
var found = data.find((item) => {
return item.value == value
})
if (found) {
result.push(found)
}
}
return result
},
_dispatchEvent(selected) {
let item = {}
if (selected.length) {
var value = new Array(selected.length)
for (var i = 0; i < selected.length; i++) {
value[i] = selected[i].value
}
item = selected[selected.length - 1]
} else {
item.value = ''
}
if (this.formItem) {
this.formItem.setValue(item.value)
}
this.$emit('input', item.value)
this.$emit('update:modelValue', item.value)
this.$emit('change', {
detail: {
value: selected
}
})
}
}
}
</script>
<style >
.uni-data-tree {
flex: 1;
position: relative;
font-size: 14px;
}
.error-text {
color: #DD524D;
}
.input-value {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
flex-wrap: nowrap;
font-size: 14px;
/* line-height: 35px; */
padding: 0 10px;
padding-right: 5px;
overflow: hidden;
height: 35px;
/* #ifndef APP-NVUE */
box-sizing: border-box;
/* #endif */
}
.input-value-border {
border: 1px solid #e5e5e5;
border-radius: 5px;
}
.selected-area {
flex: 1;
overflow: hidden;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
}
.load-more {
/* #ifndef APP-NVUE */
margin-right: auto;
/* #endif */
/* #ifdef APP-NVUE */
width: 40px;
/* #endif */
}
.selected-list {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: nowrap;
/* padding: 0 5px; */
}
.selected-item {
flex-direction: row;
/* padding: 0 1px; */
/* #ifndef APP-NVUE */
white-space: nowrap;
/* #endif */
}
.text-color {
color: #333;
}
.placeholder {
color: grey;
font-size: 12px;
}
.input-split-line {
opacity: .5;
}
.arrow-area {
position: relative;
width: 20px;
/* #ifndef APP-NVUE */
margin-bottom: 5px;
margin-left: auto;
display: flex;
/* #endif */
justify-content: center;
transform: rotate(-45deg);
transform-origin: center;
}
.input-arrow {
width: 7px;
height: 7px;
border-left: 1px solid #999;
border-bottom: 1px solid #999;
}
.uni-data-tree-cover {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, .4);
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
z-index: 100;
}
.uni-data-tree-dialog {
position: fixed;
left: 0;
top: 20%;
right: 0;
bottom: 0;
background-color: #FFFFFF;
border-top-left-radius: 10px;
border-top-right-radius: 10px;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
z-index: 102;
overflow: hidden;
/* #ifdef APP-NVUE */
width: 750rpx;
/* #endif */
}
.dialog-caption {
position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
/* border-bottom: 1px solid #f0f0f0; */
}
.title-area {
/* #ifndef APP-NVUE */
/* display: flex; */
/* #endif */
align-items: center;
/* #ifndef APP-NVUE */
margin: auto;
/* #endif */
padding: 0 10px;
}
.dialog-title {
/* font-weight: bold; */
line-height: 44px;
}
.dialog-close {
position: absolute;
top: 0;
right: 0;
bottom: 0;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
align-items: center;
padding: 0 15px;
}
.dialog-close-plus {
width: 16px;
height: 2px;
background-color: #666;
border-radius: 2px;
transform: rotate(45deg);
}
.dialog-close-rotate {
position: absolute;
transform: rotate(-45deg);
}
.picker-view {
flex: 1;
overflow: hidden;
}
.icon-clear {
display: flex;
align-items: center;
}
/* #ifdef H5 */
@media all and (min-width: 768px) {
.uni-data-tree-cover {
background-color: transparent;
}
.uni-data-tree-dialog {
position: absolute;
top: 55px;
height: auto;
min-height: 400px;
max-height: 50vh;
background-color: #fff;
border: 1px solid #EBEEF5;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
border-radius: 4px;
overflow: unset;
}
.dialog-caption {
display: none;
}
.icon-clear {
/* margin-right: 5px; */
}
}
/* #endif */
/* picker 弹出层通用的指示小三角, todo:扩展至上下左右方向定位 */
/* #ifndef APP-NVUE */
.uni-popper__arrow,
.uni-popper__arrow::after {
position: absolute;
display: block;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
border-width: 6px;
}
.uni-popper__arrow {
filter: drop-shadow(0 2px 12px rgba(0, 0, 0, 0.03));
top: -6px;
left: 10%;
margin-right: 3px;
border-top-width: 0;
border-bottom-color: #EBEEF5;
}
.uni-popper__arrow::after {
content: " ";
top: 1px;
margin-left: -6px;
border-top-width: 0;
border-bottom-color: #fff;
}
/* #endif */
</style>
export default {
props: {
localdata: {
type: [Array, Object],
default () {
return []
}
},
spaceInfo: {
type: Object,
default () {
return {}
}
},
collection: {
type: String,
default: ''
},
action: {
type: String,
default: ''
},
field: {
type: String,
default: ''
},
orderby: {
type: String,
default: ''
},
where: {
type: [String, Object],
default: ''
},
pageData: {
type: String,
default: 'add'
},
pageCurrent: {
type: Number,
default: 1
},
pageSize: {
type: Number,
default: 20
},
getcount: {
type: [Boolean, String],
default: false
},
getone: {
type: [Boolean, String],
default: false
},
gettree: {
type: [Boolean, String],
default: false
},
manual: {
type: Boolean,
default: false
},
value: {
type: [Array, String, Number],
default () {
return []
}
},
modelValue: {
type: [Array, String, Number],
default () {
return []
}
},
preload: {
type: Boolean,
default: false
},
stepSearh: {
type: Boolean,
default: true
},
selfField: {
type: String,
default: ''
},
parentField: {
type: String,
default: ''
},
multiple: {
type: Boolean,
default: false
},
map: {
type: Object,
default() {
return {
text: "text",
value: "value"
}
}
}
},
data() {
return {
loading: false,
errorMessage: '',
loadMore: {
contentdown: '',
contentrefresh: '',
contentnomore: ''
},
dataList: [],
selected: [],
selectedIndex: 0,
page: {
current: this.pageCurrent,
size: this.pageSize,
count: 0
}
}
},
computed: {
isLocaldata() {
return !this.collection.length
},
postField() {
let fields = [this.field];
if (this.parentField) {
fields.push(`${this.parentField} as parent_value`);
}
return fields.join(',');
},
dataValue() {
let isModelValue = Array.isArray(this.modelValue) ? (this.modelValue.length > 0) : (this.modelValue !== null || this.modelValue !== undefined)
return isModelValue ? this.modelValue : this.value
},
hasValue() {
if (typeof this.dataValue === 'number') {
return true
}
return (this.dataValue != null) && (this.dataValue.length > 0)
}
},
created() {
this.$watch(() => {
var al = [];
['pageCurrent',
'pageSize',
'spaceInfo',
'value',
'modelValue',
'localdata',
'collection',
'action',
'field',
'orderby',
'where',
'getont',
'getcount',
'gettree'
].forEach(key => {
al.push(this[key])
});
return al
}, (newValue, oldValue) => {
let needReset = false
for (let i = 2; i < newValue.length; i++) {
if (newValue[i] != oldValue[i]) {
needReset = true
break
}
}
if (newValue[0] != oldValue[0]) {
this.page.current = this.pageCurrent
}
this.page.size = this.pageSize
this.onPropsChange()
})
this._treeData = []
},
methods: {
onPropsChange() {
this._treeData = []
},
getCommand(options = {}) {
/* eslint-disable no-undef */
let db = uniCloud.database(this.spaceInfo)
const action = options.action || this.action
if (action) {
db = db.action(action)
}
const collection = options.collection || this.collection
db = db.collection(collection)
const where = options.where || this.where
if (!(!where || !Object.keys(where).length)) {
db = db.where(where)
}
const field = options.field || this.field
if (field) {
db = db.field(field)
}
const orderby = options.orderby || this.orderby
if (orderby) {
db = db.orderBy(orderby)
}
const current = options.pageCurrent !== undefined ? options.pageCurrent : this.page.current
const size = options.pageSize !== undefined ? options.pageSize : this.page.size
const getCount = options.getcount !== undefined ? options.getcount : this.getcount
const getTree = options.gettree !== undefined ? options.gettree : this.gettree
const getOptions = {
getCount,
getTree
}
if (options.getTreePath) {
getOptions.getTreePath = options.getTreePath
}
db = db.skip(size * (current - 1)).limit(size).get(getOptions)
return db
},
getNodeData(callback) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
where: this._pathWhere()
}).then((res) => {
this.loading = false
this.selected = res.result.data
callback && callback()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
getTreePath(callback) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
getTreePath: {
startWith: `${this.selfField}=='${this.dataValue}'`
}
}).then((res) => {
this.loading = false
let treePath = []
this._extractTreePath(res.result.data, treePath)
this.selected = treePath
callback && callback()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
loadData() {
if (this.isLocaldata) {
this._processLocalData()
return
}
if (this.dataValue != null) {
this._loadNodeData((data) => {
this._treeData = data
this._updateBindData()
this._updateSelected()
})
return
}
if (this.stepSearh) {
this._loadNodeData((data) => {
this._treeData = data
this._updateBindData()
})
} else {
this._loadAllData((data) => {
this._treeData = []
this._extractTree(data, this._treeData, null)
this._updateBindData()
})
}
},
_loadAllData(callback) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
gettree: true,
startwith: `${this.selfField}=='${this.dataValue}'`
}).then((res) => {
this.loading = false
callback(res.result.data)
this.onDataChange()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
_loadNodeData(callback, pw) {
if (this.loading) {
return
}
this.loading = true
this.getCommand({
field: this.postField,
where: pw || this._postWhere(),
pageSize: 500
}).then((res) => {
this.loading = false
callback(res.result.data)
this.onDataChange()
}).catch((err) => {
this.loading = false
this.errorMessage = err
})
},
_pathWhere() {
let result = []
let where_field = this._getParentNameByField();
if (where_field) {
result.push(`${where_field} == '${this.dataValue}'`)
}
if (this.where) {
return `(${this.where}) && (${result.join(' || ')})`
}
return result.join(' || ')
},
_postWhere() {
let result = []
let selected = this.selected
let parentField = this.parentField
if (parentField) {
result.push(`${parentField} == null || ${parentField} == ""`)
}
if (selected.length) {
for (var i = 0; i < selected.length - 1; i++) {
result.push(`${parentField} == '${selected[i].value}'`)
}
}
let where = []
if (this.where) {
where.push(`(${this.where})`)
}
if (result.length) {
where.push(`(${result.join(' || ')})`)
}
return where.join(' && ')
},
_nodeWhere() {
let result = []
let selected = this.selected
if (selected.length) {
result.push(`${this.parentField} == '${selected[selected.length - 1].value}'`)
}
if (this.where) {
return `(${this.where}) && (${result.join(' || ')})`
}
return result.join(' || ')
},
_getParentNameByField() {
const fields = this.field.split(',');
let where_field = null;
for (let i = 0; i < fields.length; i++) {
const items = fields[i].split('as');
if (items.length < 2) {
continue;
}
if (items[1].trim() === 'value') {
where_field = items[0].trim();
break;
}
}
return where_field
},
_isTreeView() {
return (this.parentField && this.selfField)
},
_updateSelected() {
var dl = this.dataList
var sl = this.selected
let textField = this.map.text
let valueField = this.map.value
for (var i = 0; i < sl.length; i++) {
var value = sl[i].value
var dl2 = dl[i]
for (var j = 0; j < dl2.length; j++) {
var item2 = dl2[j]
if (item2[valueField] === value) {
sl[i].text = item2[textField]
break
}
}
}
},
_updateBindData(node) {
const {
dataList,
hasNodes
} = this._filterData(this._treeData, this.selected)
let isleaf = this._stepSearh === false && !hasNodes
if (node) {
node.isleaf = isleaf
}
this.dataList = dataList
this.selectedIndex = dataList.length - 1
if (!isleaf && this.selected.length < dataList.length) {
this.selected.push({
value: null,
text: "请选择"
})
}
return {
isleaf,
hasNodes
}
},
_filterData(data, paths) {
let dataList = []
let hasNodes = true
dataList.push(data.filter((item) => {
return (item.parent_value === null || item.parent_value === undefined || item.parent_value === '')
}))
for (let i = 0; i < paths.length; i++) {
var value = paths[i].value
var nodes = data.filter((item) => {
return item.parent_value === value
})
if (nodes.length) {
dataList.push(nodes)
} else {
hasNodes = false
}
}
return {
dataList,
hasNodes
}
},
_extractTree(nodes, result, parent_value) {
let list = result || []
let valueField = this.map.value
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i]
let child = {}
for (let key in node) {
if (key !== 'children') {
child[key] = node[key]
}
}
if (parent_value !== null && parent_value !== undefined && parent_value !== '') {
child.parent_value = parent_value
}
result.push(child)
let children = node.children
if (children) {
this._extractTree(children, result, node[valueField])
}
}
},
_extractTreePath(nodes, result) {
let list = result || []
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i]
let child = {}
for (let key in node) {
if (key !== 'children') {
child[key] = node[key]
}
}
result.push(child)
let children = node.children
if (children) {
this._extractTreePath(children, result)
}
}
},
_findNodePath(key, nodes, path = []) {
let textField = this.map.text
let valueField = this.map.value
for (let i = 0; i < nodes.length; i++) {
let node = nodes[i]
let children = node.children
let text = node[textField]
let value = node[valueField]
path.push({
value,
text
})
if (value === key) {
return path
}
if (children) {
const p = this._findNodePath(key, children, path)
if (p.length) {
return p
}
}
path.pop()
}
return []
},
_processLocalData() {
this._treeData = []
this._extractTree(this.localdata, this._treeData)
var inputValue = this.dataValue
if (inputValue === undefined) {
return
}
if (Array.isArray(inputValue)) {
inputValue = inputValue[inputValue.length - 1]
if (typeof inputValue === 'object' && inputValue[this.map.value]) {
inputValue = inputValue[this.map.value]
}
}
this.selected = this._findNodePath(inputValue, this.localdata)
}
}
}
<template>
<view class="uni-data-pickerview">
<scroll-view class="selected-area" scroll-x="true" scroll-y="false" :show-scrollbar="false">
<view class="selected-list">
<template v-for="(item,index) in selected">
<view class="selected-item"
:class="{'selected-item-active':index==selectedIndex, 'selected-item-text-overflow': ellipsis}"
v-if="item.text" @click="handleSelect(index)">
<text class="">{{item.text}}</text>
</view>
</template>
</view>
</scroll-view>
<view class="tab-c">
<template v-for="(child, i) in dataList" >
<scroll-view class="list" :key="i" v-if="i==selectedIndex" :scroll-y="true">
<view class="item" :class="{'is-disabled': !!item.disable}" v-for="(item, j) in child"
@click="handleNodeClick(item, i, j)">
<text class="item-text item-text-overflow">{{item[map.text]}}</text>
<view class="check" v-if="selected.length > i && item[map.value] == selected[i].value"></view>
</view>
</scroll-view>
</template>
<view class="loading-cover" v-if="loading">
<uni-load-more class="load-more" :contentText="loadMore" status="loading"></uni-load-more>
</view>
<view class="error-message" v-if="errorMessage">
<text class="error-text">{{errorMessage}}</text>
</view>
</view>
</view>
</template>
<script>
import dataPicker from "./uni-data-picker.js"
/**
* DataPickerview
* @description uni-data-pickerview
* @tutorial https://ext.dcloud.net.cn/plugin?id=3796
* @property {Array} localdata 本地数据,参考
* @property {Boolean} step-searh = [true|false] 是否分布查询
* @value true 启用分布查询,仅查询当前选中节点
* @value false 关闭分布查询,一次查询出所有数据
* @property {String|DBFieldString} self-field 分布查询当前字段名称
* @property {String|DBFieldString} parent-field 分布查询父字段名称
* @property {String|DBCollectionString} collection 表名
* @property {String|DBFieldString} field 查询字段,多个字段用 `,` 分割
* @property {String} orderby 排序字段及正序倒叙设置
* @property {String|JQLString} where 查询条件
*/
export default {
name: 'UniDataPickerView',
emits: ['nodeclick', 'change', 'datachange', 'update:modelValue'],
mixins: [dataPicker],
props: {
managedMode: {
type: Boolean,
default: false
},
ellipsis: {
type: Boolean,
default: true
}
},
data() {
return {}
},
created() {
if (this.managedMode) {
return
}
this.$nextTick(() => {
this.load()
})
},
methods: {
onPropsChange() {
this._treeData = []
this.selectedIndex = 0
this.load()
},
load() {
if (this.isLocaldata) {
this.loadData()
} else if (this.dataValue.length) {
this.getTreePath((res) => {
this.loadData()
})
}
},
handleSelect(index) {
this.selectedIndex = index
},
handleNodeClick(item, i, j) {
if (item.disable) {
return
}
const node = this.dataList[i][j]
const text = node[this.map.text]
const value = node[this.map.value]
if (i < this.selected.length - 1) {
this.selected.splice(i, this.selected.length - i)
this.selected.push({
text,
value
})
} else if (i === this.selected.length - 1) {
this.selected.splice(i, 1, {
text,
value
})
}
if (node.isleaf) {
this.onSelectedChange(node, node.isleaf)
return
}
const {
isleaf,
hasNodes
} = this._updateBindData()
if (!this._isTreeView() && !hasNodes) {
this.onSelectedChange(node, true)
return
}
if (this.isLocaldata && (!hasNodes || isleaf)) {
this.onSelectedChange(node, true)
return
}
if (!isleaf && !hasNodes) {
this._loadNodeData((data) => {
if (!data.length) {
node.isleaf = true
} else {
this._treeData.push(...data)
this._updateBindData(node)
}
this.onSelectedChange(node, node.isleaf)
}, this._nodeWhere())
return
}
this.onSelectedChange(node, false)
},
updateData(data) {
this._treeData = data.treeData
this.selected = data.selected
if (!this._treeData.length) {
this.loadData()
} else {
//this.selected = data.selected
this._updateBindData()
}
},
onDataChange() {
this.$emit('datachange')
},
onSelectedChange(node, isleaf) {
if (isleaf) {
this._dispatchEvent()
}
if (node) {
this.$emit('nodeclick', node)
}
},
_dispatchEvent() {
this.$emit('change', this.selected.slice(0))
}
}
}
</script>
<style lang="scss">
$uni-primary: #007aff !default;
.uni-data-pickerview {
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
overflow: hidden;
height: 100%;
}
.error-text {
color: #DD524D;
}
.loading-cover {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: rgba(255, 255, 255, .5);
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
align-items: center;
z-index: 1001;
}
.load-more {
/* #ifndef APP-NVUE */
margin: auto;
/* #endif */
}
.error-message {
background-color: #fff;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
padding: 15px;
opacity: .9;
z-index: 102;
}
/* #ifdef APP-NVUE */
.selected-area {
width: 750rpx;
}
/* #endif */
.selected-list {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
flex-wrap: nowrap;
padding: 0 5px;
border-bottom: 1px solid #f8f8f8;
}
.selected-item {
margin-left: 10px;
margin-right: 10px;
padding: 12px 0;
text-align: center;
/* #ifndef APP-NVUE */
white-space: nowrap;
/* #endif */
}
.selected-item-text-overflow {
width: 168px;
/* fix nvue */
overflow: hidden;
/* #ifndef APP-NVUE */
width: 6em;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
/* #endif */
}
.selected-item-active {
border-bottom: 2px solid $uni-primary;
}
.selected-item-text {
color: $uni-primary;
}
.tab-c {
position: relative;
flex: 1;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
overflow: hidden;
}
.list {
flex: 1;
}
.item {
padding: 12px 15px;
/* border-bottom: 1px solid #f0f0f0; */
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
justify-content: space-between;
}
.is-disabled {
opacity: .5;
}
.item-text {
/* flex: 1; */
color: #333333;
}
.item-text-overflow {
width: 280px;
/* fix nvue */
overflow: hidden;
/* #ifndef APP-NVUE */
width: 20em;
white-space: nowrap;
text-overflow: ellipsis;
-o-text-overflow: ellipsis;
/* #endif */
}
.check {
margin-right: 5px;
border: 2px solid $uni-primary;
border-left: 0;
border-top: 0;
height: 12px;
width: 6px;
transform-origin: center;
/* #ifndef APP-NVUE */
transition: all 0.3s;
/* #endif */
transform: rotate(45deg);
}
</style>
{
"id": "uni-data-picker",
"displayName": "uni-data-picker 数据驱动的picker选择器",
"version": "1.0.8",
"description": "单列、多列级联选择器,常用于省市区城市选择、公司部门选择、多级分类等场景",
"keywords": [
"uni-ui",
"uniui",
"picker",
"级联",
"省市区",
""
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui",
"type": "component-vue"
},
"uni_modules": {
"dependencies": [
"uni-load-more",
"uni-icons",
"uni-scss"
],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "u"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}
\ No newline at end of file
## DataPicker 级联选择
> **组件名:uni-data-picker**
> 代码块: `uDataPicker`
> 关联组件:`uni-data-pickerview`、`uni-load-more`。
`<uni-data-picker>` 是一个选择类[datacom组件](https://uniapp.dcloud.net.cn/component/datacom)
支持单列、和多列级联选择。列数没有限制,如果屏幕显示不全,顶部tab区域会左右滚动。
候选数据支持一次性加载完毕,也支持懒加载,比如示例图中,选择了“北京”后,动态加载北京的区县数据。
`<uni-data-picker>` 组件尤其适用于地址选择、分类选择等选择类。
`<uni-data-picker>` 支持本地数据、云端静态数据(json),uniCloud云数据库数据。
`<uni-data-picker>` 可以通过JQL直连uniCloud云数据库,配套[DB Schema](https://uniapp.dcloud.net.cn/uniCloud/schema),可在schema2code中自动生成前端页面,还支持服务器端校验。
在uniCloud数据表中新建表“uni-id-address”和“opendb-city-china”,这2个表的schema自带foreignKey关联。在“uni-id-address”表的表结构页面使用schema2code生成前端页面,会自动生成地址管理的维护页面,自动从“opendb-city-china”表包含的中国所有省市区信息里选择地址。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-data-picker)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
\ No newline at end of file
## 1.3.3(2022-01-20)
- 新增 showText属性 ,是否显示文本
## 1.3.2(2022-01-19)
- 修复 nvue 平台下不显示文本的bug
## 1.3.1(2022-01-19)
- 修复 微信小程序平台样式选择器报警告的问题
## 1.3.0(2021-11-19)
- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource)
- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-load-more](https://uniapp.dcloud.io/component/uniui/uni-load-more)
## 1.2.1(2021-08-24)
- 新增 支持国际化
## 1.2.0(2021-07-30)
- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834)
## 1.1.8(2021-05-12)
- 新增 组件示例地址
## 1.1.7(2021-03-30)
- 修复 uni-load-more 在首页使用时,h5 平台报 'uni is not defined' 的 bug
## 1.1.6(2021-02-05)
- 调整为uni_modules目录规范
{
"uni-load-more.contentdown": "Pull up to show more",
"uni-load-more.contentrefresh": "loading...",
"uni-load-more.contentnomore": "No more data"
}
import en from './en.json'
import zhHans from './zh-Hans.json'
import zhHant from './zh-Hant.json'
export default {
en,
'zh-Hans': zhHans,
'zh-Hant': zhHant
}
{
"uni-load-more.contentdown": "上拉显示更多",
"uni-load-more.contentrefresh": "正在加载...",
"uni-load-more.contentnomore": "没有更多数据了"
}
{
"uni-load-more.contentdown": "上拉顯示更多",
"uni-load-more.contentrefresh": "正在加載...",
"uni-load-more.contentnomore": "沒有更多數據了"
}
<template>
<view class="uni-load-more" @click="onClick">
<!-- #ifdef APP-NVUE -->
<loading-indicator v-if="!webviewHide && status === 'loading' && showIcon"
:style="{color: color,width:iconSize+'px',height:iconSize+'px'}" :animating="true"
class="uni-load-more__img uni-load-more__img--nvue"></loading-indicator>
<!-- #endif -->
<!-- #ifdef H5 -->
<svg width="24" height="24" viewBox="25 25 50 50"
v-if="!webviewHide && (iconType==='circle' || iconType==='auto' && platform === 'android') && status === 'loading' && showIcon"
:style="{width:iconSize+'px',height:iconSize+'px'}"
class="uni-load-more__img uni-load-more__img--android-H5">
<circle cx="50" cy="50" r="20" fill="none" :style="{color:color}" :stroke-width="3"></circle>
</svg>
<!-- #endif -->
<!-- #ifndef APP-NVUE || H5 -->
<view
v-if="!webviewHide && (iconType==='circle' || iconType==='auto' && platform === 'android') && status === 'loading' && showIcon"
:style="{width:iconSize+'px',height:iconSize+'px'}"
class="uni-load-more__img uni-load-more__img--android-MP">
<view class="uni-load-more__img-icon" :style="{borderTopColor:color,borderTopWidth:iconSize/12}"></view>
<view class="uni-load-more__img-icon" :style="{borderTopColor:color,borderTopWidth:iconSize/12}"></view>
<view class="uni-load-more__img-icon" :style="{borderTopColor:color,borderTopWidth:iconSize/12}"></view>
</view>
<!-- #endif -->
<!-- #ifndef APP-NVUE -->
<view v-else-if="!webviewHide && status === 'loading' && showIcon"
:style="{width:iconSize+'px',height:iconSize+'px'}" class="uni-load-more__img uni-load-more__img--ios-H5">
<image :src="imgBase64" mode="widthFix"></image>
</view>
<!-- #endif -->
<text v-if="showText" class="uni-load-more__text"
:style="{color: color}">{{ status === 'more' ? contentdownText : status === 'loading' ? contentrefreshText : contentnomoreText }}</text>
</view>
</template>
<script>
let platform
setTimeout(() => {
platform = uni.getSystemInfoSync().platform
}, 16)
import {
initVueI18n
} from '@dcloudio/uni-i18n'
import messages from './i18n/index.js'
const {
t
} = initVueI18n(messages)
/**
* LoadMore 加载更多
* @description 用于列表中,做滚动加载使用,展示 loading 的各种状态
* @tutorial https://ext.dcloud.net.cn/plugin?id=29
* @property {String} status = [more|loading|noMore] loading 的状态
* @value more loading前
* @value loading loading中
* @value noMore 没有更多了
* @property {Number} iconSize 指定图标大小
* @property {Boolean} iconSize = [true|false] 是否显示 loading 图标
* @property {String} iconType = [snow|circle|auto] 指定图标样式
* @value snow ios雪花加载样式
* @value circle 安卓唤醒加载样式
* @value auto 根据平台自动选择加载样式
* @property {String} color 图标和文字颜色
* @property {Object} contentText 各状态文字说明,值为:{contentdown: "上拉显示更多",contentrefresh: "正在加载...",contentnomore: "没有更多数据了"}
* @event {Function} clickLoadMore 点击加载更多时触发
*/
export default {
name: 'UniLoadMore',
emits: ['clickLoadMore'],
props: {
status: {
// 上拉的状态:more-loading前;loading-loading中;noMore-没有更多了
type: String,
default: 'more'
},
showIcon: {
type: Boolean,
default: true
},
iconType: {
type: String,
default: 'auto'
},
iconSize: {
type: Number,
default: 24
},
color: {
type: String,
default: '#777777'
},
contentText: {
type: Object,
default () {
return {
contentdown: '',
contentrefresh: '',
contentnomore: ''
}
}
},
showText: {
type: Boolean,
default: true
}
},
data() {
return {
webviewHide: false,
platform: platform,
imgBase64: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoV2luZG93cykiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6QzlBMzU3OTlEOUM0MTFFOUI0NTZDNERBQURBQzI4RkUiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6QzlBMzU3OUFEOUM0MTFFOUI0NTZDNERBQURBQzI4RkUiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDpDOUEzNTc5N0Q5QzQxMUU5QjQ1NkM0REFBREFDMjhGRSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDpDOUEzNTc5OEQ5QzQxMUU5QjQ1NkM0REFBREFDMjhGRSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pt+ALSwAAA6CSURBVHja1FsLkFZVHb98LM+F5bHL8khA1iSeiyQBCRM+YGqKUnnJTDLGI0BGZlKDIU2MMglUiDApEZvSsZnQtBRJtKwQNKQMFYeRDR10WOLd8ljYXdh+v8v5fR3Od+797t1dnOnO/Ofce77z+J//+b/P+ZqtXbs2sJ9MJhNUV1cHJ06cCJo3bx7EPc2aNcvpy7pWrVoF+/fvDyoqKoI2bdoE9fX1F7TjN8a+EXBn/fkfvw942Tf+wYMHg9mzZwfjxo0LDhw4EPa1x2MbFw/fOGfPng1qa2tzcCkILsLDydq2bRsunpOTMM7TD/W/tZDZhPdeKD+yGxHhdu3aBV27dg3OnDlzMVANMheLAO3btw8KCwuDmpoaX5OxbgUIMEq7K8IcPnw4KCsrC/r37x8cP378/4cAXAB3vqSkJMuiDhTkw+XcuXNhOWbMmKBly5YhUT8xArhyFvP0BfwRsAuwxJZJsm/nzp2DTp06he/OU+cZ64K6o0ePBkOHDg2GDx8e6gEbJ5Q/NHNuAJQ1hgBeHUDlR7nVTkY8rQAvAi4z34vR/mPs1FoRsaCgIJThI0eOBC1atEiFGGV+5MiRoS45efJkqFjJFXV1dQuA012m2WcwTw98fy6CqBdsaiIO4CScrGPHjvk4odhavPquRtFWXEC25VgkREKOCh/qDSq+vn37htzD/mZTOmOc5U7zKzBPEedygWshcDyWvs30igAbU+6oyMgJBCFhwQE0fccxN60Ay9iebbjoDh06hMowjQxT4fXq1SskArmHZpkArvixp/kWzHdMeArExSJEaiXIjjRjRJ4DaAGWpibLzXN3Fm1vA5teBgh3j1Rv3bp1YgKwPdmf2p9zcyNYYgPKMfY0T5f5nNYdw158nJ8QawW4CLKwiOBSEgO/hok2eBydR+3dYH+PLxA5J8Vv0KBBwenTp0P2JWAx6+yFEBfs8lMY+y0SWMBNI9E4ThKi58VKTg3FQZS1RQF1cz27eC0QHMu+3E0SkUowjhVt5VdaWhp07949ZHv2Qd1EjDXM2cla1M0nl3GxAs3J9yREzyTdFVKVFOaE9qRA8GM0WebRuo9JGZKA7Mv2SeS/Z8+eoQ9BArMfFrLGo6jvxbhHbJZnKX2Rzz1O7QhJJ9Cs2ZMaWIyq/zhdeqPNfIoHd58clIQD+JSXl4dKlyIAuBdVXZwFVWKspSSoxE++h8x4k3uCnEhE4I5KwRiFWGOU0QWKiCYLbdoRMRKAu2kQ9vkfLU6dOhX06NEjlH+yMRZSinnuyWnYosVcji8CEA/6Cg2JF+IIUBqnGKUTCNwtwBN4f89RiK1R96DEgO2o0NDmtEdvVFdVVYV+P3UAPUEs6GFwV3PHmXkD4vh74iDFJysVI/MlaQhwKeBNTLYX5VuA8T4/gZxA4MRGFxDB6R7OmYPfyykGRJbyie+XnGYnQIC/coH9+vULiYrxrkL9ZA9+0ykaHIfEpM7ge8TiJ2CsHYwyMfafAF1yCGBHYIbCVDjDjKt7BeB51D+LgQa6OkG7IDYEEtvQ7lnXLKLtLdLuJBpE4gPUXcW2+PkZwOex+4cGDhwYDBkyRL7/HFcEwUGPo/8uWRUpYnfxGHco8HkewLHLyYmAawAPuIFZxhOpDfJQ8gbUv41yORAptMWBNr6oqMhWird5+u+iHmBb2nhjDV7HWBNQTgK8y11l5NetWzc5ULscAtSj7nbNI0skhWeUZCc0W4nyH/jO4Vz0u1IeYhbk4AiwM6tjxIWByHsoZ9qcIBPJd/y+DwPfBESOmCa/QF3WiZHucLlEDpNxcNhmheEOPgdQNx6/VZFQzFZ5TN08AHXQt2Ii3EdyFuUsPtTcGPhW5iMiCNELvz+Gdn9huG4HUJaW/w3g0wxV0XaG7arG2WeKiUWYM4Y7GO5ezshTARbbWGw/DvXkpp/ivVvE0JVoMxN4rpGzJMhE5Pl+xlATsDIqikP9F9D2z3h9nOksEUFhK+qO4rcPkoalMQ/HqJLIyb3F3JdjrCcw1yZ8joyJLR5gCo54etlag7qIoeNh1N1BRYj3DTFJ0elotxPlVzkGuYAmL0VSJVGAJA41c4Z6A3BzTLfn0HYwYKEI6CUAMzZEWvLsIcQOo1AmmyyM72nHJCfYsogflGV6jEk9vyQZXSuq6w4c16NsGcGZbwOPr+H1RkOk2LEzjNepxQkihHSCQ4ynAYNRx2zMKV92CQMWqj8J0BRE8EShxRFN6YrfCRhC0x3r/Zm4IbQCcmJoV0kMamllccR6FjHqUC5F2R/wS2dcymOlfAKOS4KmzQb5cpNC2MC7JhVn5wjXoJ44rYhLh8n0eXOCorJxa7POjbSlCGVczr34/RsAmrcvo9s+wGp3tzVhntxiXiJ4nvEYb4FJkf0O8HocAePmLvCxnL0AORraVekJk6TYjDabRVXfRE2lCN1h6ZQRN1+InUbsCpKwoBZHh0dODN9JBCUffItXxEavTQkUtnfTVAplCWL3JISz29h4NjotnuSsQKJCk8dF+kJR6RARjrqFVmfPnj3ZbK8cIJ0msd6jgHPGtfVTQ8VLmlvh4mct9sobRmPic0DyDQQnx/NlfYUgyz59+oScsH379pAwXABD32nTpoUHIToESeI5mnbE/UqDdyLcafEBf2MCqgC7NwxIbMREJQ0g4D4sfJwnD+AmRrII05cfMWJE+L1169bQr+fip06dGp4oJ83lmYd5wj/EmMa4TaHivo4EeCguYZBnkB5g2aWA69OIEnUHOaGysjIYMGBAMGnSpODYsWPZwCpFmm4lNq+4gSLQA7jcX8DwtjEyRC8wjabnXEx9kfWnTJkSJkAo90xpJVV+FmcVNeYAF5zWngS4C4O91MBxmAv8blLEpbjI5sz9MTdAhcgkCT1RO8mZkAjfiYpTEvStAS53Uw1vAiUGgZ3GpuQEYvoiBqlIan7kSDHnTwJQFNiPu0+5VxCVYhcZIjNrdXUDdp+Eq5AZ3Gkg8QAyVZRZIk4Tl4QAbF9cXJxNYZMAtAokgs4BrNxEpCtteXg7DDTMDKYNSuQdKsnJBek7HxewvxaosWxLYXtw+cJp18217wql4aKCfBNoEu0O5VU+PhctJ0YeXD4C6JQpyrlpSLTojpGGGN5YwNziChdIZLk4lvLcFJ9jMX3QdiImY9bmGQU+TRUL5CHITTRlgF8D9ouD1MfmLoEPl5xokIumZ2cfgMpHt47IW9N64Hsh7wQYYjyIugWuF5fCqYncXRd5vPMWyizzvhi/32+nvG0dZc9vR6fZOu0md5e+uC408FvKSIOZwXlGvxPv95izA2Vtvg1xKFWARI+vMX66HUhpQQb643uW1bSjuTWyw2SBvDrBvjFic1eGGlz5esq3ko9uSIlBRqPuFcCv8F4WIcN12nVaBd0SaYwI6PDDImR11JkqgHcPmQssjxIn6bUshygDFJUTxPMpHk+jfjPgupgdnYV2R/g7xSjtpah8RJBewhwf0gGK6XI92u4wXFEU40afJ4DN4h5LcAd+40HI3JgJecuT0c062W0i2hQJUTcxan3/CMW1PF2K6bbA+Daz4xRs1D3Br1Cm0OihKCqizW78/nXAF/G5TXrEcVzaNMH6CyMswqsAHqDyDLEyou8lwOXnKF8DjI6KjV3KzMBiXkDH8ij/H214J5A596ekrZ3F0zXlWeL7+P5eUrNo3/QwC15uxthuzidy7DzKRwEDaAViiDgKbTbz7CJnzo0bN7pIfIiid8SuPwn25o3QCmpnyjlZkyxPP8EomCJzrGb7GJMx7tNsq4MT2xMUYaiErZOluTzKsnz3gwCeCZyVRZJfYplNEokEjwrPtxlxjeYAk+F1F74VAzPxQRNYYdtpOUvWs8J1sGhBJMNsb7igN8plJs1eSmLIhLKE4rvaCX27gOhLpLOsIzJ7qn/i+wZzcvSOZ23/du8TZjwV8zHIXoP4R3ifBxiFz1dcVpa3aPntPE+c6TmIWE9EtcMmAcPdWAhYhAXxcLOQi9L1WhD1Sc8p1d2oL7XGiRKp8F4A2i8K/nfI+y/gsTDJ/YC/8+AD5Uh04KHiGl+cIFPnBDDrPMjwRGkLXyxO4VGbfQWnDH2v0bVWE3C9QOXlepbgjEfIJQI6XDG3z5ahD9cw2pS78ipB85wyScNTvsVzlzzhL8/jRrnmVjfFJK/m3m4nj9vbgQTguT8XZTjsm672R5uJKEaQmBI/c58gyus8ZDagLpEVSJBIyHp4jn++xqPV71OgQgJYEWOtZ/haxRtKmWOBu8xdBLftWltsY84zE6WIEy/eIOWL+BaayMx+KHtL7EAkqdNDLiEXmEMUHniedtJqg9HmZtfvt26vNi0BdG3Ft3g8ZOf7PAu59TxtzivLNIekyi+wD1i8CuUiD9FXAa8C+/xS3JPmZnomyc7H+fb4/Se0bk41Fel621r4cgVxbq91V4jVqwB7HTe2M7jgB+QWHavZkDRPmZcASoZEmBx6i75bGjPcMdL4/VKGFAGWZkGzPG0XAbdL9A81G5LOmUnC9hHKJeO7dcUMjblSl12867ElFTtaGl20xvvLGPdVz/8TVuU7y0x1PG7vtNg24oz9Uo/Z412++VFWI7Fcog9tu9Lm6gvRmIPv9x1xmQAu6RDkXtbOtlGEmpgD5Nvnyc0dcv0EE6cfdi1HmhMf9wDF3k3gtRvEedhxjpgfqPb9PU9iEJHnyOUA7bQUXh6kq/D7l2iTjWv7XOD530BDr8jIrus+srXjt4MzumJMHuTsBa63YKE1+RR5lBjEikCCnWKWiHdzOgKO+nRIBAF88za/IFmJ3eMZov4CYxGBabcpGL8EYx+SeMXJeRwHNsV/h+vdxeuhEpN3ZyNY78Gm2fknJxVGhyjixPiQvVkNzT1elD9Py/aTAL64Hb9vcYmC9zfdXdT/C1LeGbg4rnBaAihDFJH12W5ulfNCNe/xTsP3bp8ikzJs5BF+5PNfAQYAPaseTdsEcaYAAAAASUVORK5CYII='
}
},
computed: {
iconSnowWidth() {
return (Math.floor(this.iconSize / 24) || 1) * 2
},
contentdownText() {
return this.contentText.contentdown || t("uni-load-more.contentdown")
},
contentrefreshText() {
return this.contentText.contentrefresh || t("uni-load-more.contentrefresh")
},
contentnomoreText() {
return this.contentText.contentnomore || t("uni-load-more.contentnomore")
}
},
mounted() {
// #ifdef APP-PLUS
var pages = getCurrentPages();
var page = pages[pages.length - 1];
var currentWebview = page.$getAppWebview();
currentWebview.addEventListener('hide', () => {
this.webviewHide = true
})
currentWebview.addEventListener('show', () => {
this.webviewHide = false
})
// #endif
},
methods: {
onClick() {
this.$emit('clickLoadMore', {
detail: {
status: this.status,
}
})
}
}
}
</script>
<style lang="scss" >
.uni-load-more {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: row;
height: 40px;
align-items: center;
justify-content: center;
}
.uni-load-more__text {
font-size: 14px;
margin-left: 8px;
}
.uni-load-more__img {
width: 24px;
height: 24px;
// margin-right: 8px;
}
.uni-load-more__img--nvue {
color: #666666;
}
.uni-load-more__img--android,
.uni-load-more__img--ios {
width: 24px;
height: 24px;
transform: rotate(0deg);
}
/* #ifndef APP-NVUE */
.uni-load-more__img--android {
animation: loading-ios 1s 0s linear infinite;
}
@keyframes loading-android {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.uni-load-more__img--ios-H5 {
position: relative;
animation: loading-ios-H5 1s 0s step-end infinite;
}
.uni-load-more__img--ios-H5 image {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
}
@keyframes loading-ios-H5 {
0% {
transform: rotate(0deg);
}
8% {
transform: rotate(30deg);
}
16% {
transform: rotate(60deg);
}
24% {
transform: rotate(90deg);
}
32% {
transform: rotate(120deg);
}
40% {
transform: rotate(150deg);
}
48% {
transform: rotate(180deg);
}
56% {
transform: rotate(210deg);
}
64% {
transform: rotate(240deg);
}
73% {
transform: rotate(270deg);
}
82% {
transform: rotate(300deg);
}
91% {
transform: rotate(330deg);
}
100% {
transform: rotate(360deg);
}
}
/* #endif */
/* #ifdef H5 */
.uni-load-more__img--android-H5 {
animation: loading-android-H5-rotate 2s linear infinite;
transform-origin: center center;
}
.uni-load-more__img--android-H5 circle {
display: inline-block;
animation: loading-android-H5-dash 1.5s ease-in-out infinite;
stroke: currentColor;
stroke-linecap: round;
}
@keyframes loading-android-H5-rotate {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes loading-android-H5-dash {
0% {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -40;
}
100% {
stroke-dasharray: 90, 150;
stroke-dashoffset: -120;
}
}
/* #endif */
/* #ifndef APP-NVUE || H5 */
.uni-load-more__img--android-MP {
position: relative;
width: 24px;
height: 24px;
transform: rotate(0deg);
animation: loading-ios 1s 0s ease infinite;
}
.uni-load-more__img--android-MP .uni-load-more__img-icon {
position: absolute;
box-sizing: border-box;
width: 100%;
height: 100%;
border-radius: 50%;
border: solid 2px transparent;
border-top: solid 2px #777777;
transform-origin: center;
}
.uni-load-more__img--android-MP .uni-load-more__img-icon:nth-child(1) {
animation: loading-android-MP-1 1s 0s linear infinite;
}
.uni-load-more__img--android-MP .uni-load-more__img-icon:nth-child(2) {
animation: loading-android-MP-2 1s 0s linear infinite;
}
.uni-load-more__img--android-MP .uni-load-more__img-icon:nth-child(3) {
animation: loading-android-MP-3 1s 0s linear infinite;
}
@keyframes loading-android {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes loading-android-MP-1 {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(90deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes loading-android-MP-2 {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(180deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes loading-android-MP-3 {
0% {
transform: rotate(0deg);
}
50% {
transform: rotate(270deg);
}
100% {
transform: rotate(360deg);
}
}
/* #endif */
</style>
{
"id": "uni-load-more",
"displayName": "uni-load-more 加载更多",
"version": "1.3.3",
"description": "LoadMore 组件,常用在列表里面,做滚动加载使用。",
"keywords": [
"uni-ui",
"uniui",
"加载更多",
"load-more"
],
"repository": "https://github.com/dcloudio/uni-ui",
"engines": {
"HBuilderX": ""
},
"directories": {
"example": "../../temps/example_temps"
},
"dcloudext": {
"category": [
"前端组件",
"通用组件"
],
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui"
},
"uni_modules": {
"dependencies": ["uni-scss"],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y"
},
"client": {
"App": {
"app-vue": "y",
"app-nvue": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "y",
"Edge": "y",
"Firefox": "y",
"Safari": "y"
},
"小程序": {
"微信": "y",
"阿里": "y",
"百度": "y",
"字节跳动": "y",
"QQ": "y"
},
"快应用": {
"华为": "u",
"联盟": "u"
},
"Vue": {
"vue2": "y",
"vue3": "y"
}
}
}
}
}
\ No newline at end of file
### LoadMore 加载更多
> **组件名:uni-load-more**
> 代码块: `uLoadMore`
用于列表中,做滚动加载使用,展示 loading 的各种状态。
### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-load-more)
#### 如使用过程中有任何问题,或者您对uni-ui有一些好的建议,欢迎加入 uni-ui 交流群:871950839
const eduGradeLists=[
{
text: "幼儿园",
value: "1",
commonYears:3,
minAge:3,
maxAge:5,
publicTuition:9016,
privateTuition:11475,
children: [
{text: "1年级",value: "1-1",tuition:9016},
{text: "2年级",value: "1-2",tuition:null},
{text: "3年级",value: "1-3",tuition:null}
]
},
{
text: "小学",
value: "2",
commonYears:6,
minAge:6,
maxAge:12,
publicTuition:4034,
privateTuition:5738,
children: [
{text: "1年级",value: "2-1",tuition:4034},
{text: "2年级",value: "2-2",tuition:null},
{text: "3年级",value: "2-3",tuition:null},
{text: "4年级",value: "2-4",tuition:null},
{text: "5年级",value: "2-5",tuition:null},
{text: "6年级",value: "2-6",tuition:null},
]
},
{
text: "初中",
value: "3",
commonYears:3,
minAge:13,
maxAge:18,
publicTuition:6095,
privateTuition:10444,
children: [
{text: "1年级",value: "3-1",tuition:6095},
{text: "2年级",value: "3-2",tuition:null},
{text: "3年级",value: "3-3",tuition:null},
]
},
{
text: "高中",
value: "4",
commonYears:3,
minAge:19,
maxAge:22,
publicTuition:7976,
privateTuition:15952,
children: [
{text: "1年级",value: "4-1",tuition:7976},
{text: "2年级",value: "4-2",tuition:null},
{text: "3年级",value: "4-3",tuition:null},
]
},
{
text: "大学",
value: "5",
commonYears:4,
minAge:23,
maxAge:27,
publicTuition:11960,
privateTuition:17940,
children: [
{text: "1年级",value: "5-1",tuition:11960},
{text: "2年级",value: "5-2",tuition:null},
{text: "3年级",value: "5-3",tuition:null},
{text: "4年级",value: "5-4",tuition:null},
]
},
{
text: "硕士",
value: "6",
commonYears:2,
minAge:28,
maxAge:30,
publicTuition:11960,
privateTuition:17940,
children: [
{text: "1年级",value: "6-1",tuition:11960},
{text: "2年级",value: "6-2",tuition:null}
]
},
{
text: "博士",
value: "7",
commonYears:3,
minAge:31,
maxAge:34,
publicTuition:11960,
privateTuition:17940,
children: [
{text: "1年级",value: "7-1",tuition:11960},
{text: "2年级",value: "7-2",tuition:null},
{text: "3年级",value: "7-3",tuition:null}
]
}
]
export {eduGradeLists};
\ No newline at end of file
......@@ -38,7 +38,7 @@ export default function initApp(){
}
function hasPermission (url) {
let islogin = uni.getStorageSync("isLogin");//在这可以使用token、vuex
islogin = Boolean(Number(islogin));//返回布尔值
// islogin = Boolean(Number(islogin));//返回布尔值
// 在白名单中或有登录判断条件可以直接跳转
if(whiteList.indexOf(url.slice(0,url.indexOf('?'))) !== -1 || islogin) {
return true
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment