Commit e576e898 authored by 郝聪敏's avatar 郝聪敏

Merge branch 'feature/home' into 'master'

Feature/home

See merge request !28
parents 972c1cc1 07fa0346
......@@ -2,6 +2,15 @@ import good01 from "@/assets/images/goods/goods-01.png";
import good02 from "@/assets/images/goods/goods-02.png";
import good03 from "@/assets/images/goods/goods-03.png";
import good04 from "@/assets/images/goods/goods-04.png";
import medical_closed from "@/assets/images/user/medical_closed@2x.png";
import casualty_closed from "@/assets/images/user/casualty_closed@2x.png";
import illness_closed from "@/assets/images/user/illness_closed@2x.png";
import life_closed from "@/assets/images/user/life_closed@2x.png";
import medical from "@/assets/images/user/medical@2x.png";
import casualty from "@/assets/images/user/casualty@2x.png";
import illness from "@/assets/images/user/illness@2x.png";
import life from "@/assets/images/user/life@2x.png";
export default [
{
title: "住院医疗险",
......@@ -16,7 +25,12 @@ export default [
glory: "好评榜第1名",
price: "0",
unit: "",
allow: true
allow: true,
termType: "short",
icon_closed: medical_closed,
icon: medical,
guarantee_title: "医疗保障",
guarantee_sub: "看病报销医药费,最高600万"
}
]
},
......@@ -25,7 +39,7 @@ export default [
sub: "责任内疾病确诊即赔",
children: [
{
id: 1,
id: 2,
itype: "cii",
img: good02,
title: "万家保·重疾轻症险",
......@@ -33,7 +47,28 @@ export default [
glory: "",
price: "3",
unit: "首月",
allow: true
allow: true,
termType: "short",
icon_closed: illness_closed,
icon: illness,
guarantee_title: "重疾保障",
guarantee_sub: "100种重症+40种轻症"
},
{
id: 3,
itype: "cii",
img: good02,
title: "康惠保2020终身重疾险",
sub: "100种重疾+40种轻症",
glory: "",
price: "3",
unit: "首月",
allow: true,
termType: "long",
icon_closed: illness_closed,
icon: illness,
guarantee_title: "重疾保障",
guarantee_sub: "100种重症+40种轻症"
}
]
},
......@@ -42,7 +77,7 @@ export default [
sub: "意外保障无等待期",
children: [
{
id: 1,
id: 4,
itype: "ai",
img: good03,
title: "万家保·综合意外险",
......@@ -50,7 +85,12 @@ export default [
glory: "开车必备",
price: "0",
unit: "",
allow: true
allow: true,
termType: "short",
icon_closed: casualty_closed,
icon: casualty,
guarantee_title: "意外保障",
guarantee_sub: "意外风险覆盖全,最高100万保额"
}
]
},
......@@ -59,7 +99,7 @@ export default [
sub: "家庭顶梁柱必备",
children: [
{
id: 1,
id: 5,
itype: "li",
img: good04,
title: "华贵大麦2020定期寿险",
......@@ -67,7 +107,12 @@ export default [
glory: "",
price: "0",
unit: "",
allow: true
allow: true,
termType: "long",
icon_closed: life_closed,
icon: life,
guarantee_title: "人寿保障",
guarantee_sub: "最高350万保额,顶梁柱必备"
}
]
}
......
import req from "@/service/http";
// 查询订单列表
export const getPolicyList = () => {
return req.get("policy_order/list");
};
// 查询订单详情
export const addPolicyDetail = param => {
return req.post("user/info", param);
};
......@@ -24,3 +24,28 @@ export const getCaptchaSms = param => {
export const getCaptchaImg = param => {
return req.post("captcha/image", param);
};
// 获取用户信息
export const getUserInfo = () => {
return req.get("user/me");
};
// 查询家人列表
export const getFamilyList = () => {
return req.get("user/info/list");
};
// 新增个人信息
export const addFamily = param => {
return req.post("user/info", param);
};
// 修改个人信息
export const updateFamily = param => {
return req.post("/user/info/update", param);
};
// 修改个人信息
export const delFamily = param => {
return req.post("/user/info/delete", param);
};
import cherry from "@qg/cherry-ui";
const { Notify } = cherry;
export default {
methods: {
onFailed(errorInfo) {
Notify(errorInfo?.errors?.[0]?.message || '校验失败')
}
}
};
\ No newline at end of file
......@@ -14,6 +14,11 @@ const routes = [
name: "Home",
component: () => import("../views/Home/index.vue")
},
{
path: "/home/smart-measure",
name: "SmartMeasure",
component: () => import("../views/Home/SmartMeasure/index.vue")
},
{
path: "/goods",
name: "Goods",
......@@ -69,6 +74,11 @@ const routes = [
name: "Family",
component: () => import("../views/User/Family/index.vue")
},
{
path: "/user/family/detail/:id",
name: "Family",
component: () => import("../views/User/Family/Detail/index.vue")
},
{
path: "/user/help-center",
name: "Family",
......
//引入axios
import store from "@/store";
import axios from "axios";
import { Notify } from "@qg/cherry-ui";
import cherry from "@qg/cherry-ui";
import config from "../config";
// import qs from "qs";
import localStorage from "./localStorage";
const ERR_MESSAGE_MAP = {
status: {
400: "错误请求",
401: "未授权,请重新登录",
403: "拒绝访问",
404: "请求错误,未找到该资源",
405: "请求方法未允许",
408: "请求超时",
500: "服务器端出错",
501: "网络未实现",
502: "网络错误",
503: "服务不可用",
504: "网络超时",
505: "http版本不支持该请求"
}
};
const { Notify } = cherry;
const CancelToken = axios.CancelToken;
// const { Notify } = cherry;
let pending = {};
let reqNum = 0;
axios.defaults.baseURL = config.basicHost;
axios.defaults.timeout = 30000;
// let cancel;
let pending = {};
let reqNum = 0;
function beforeRequest() {
reqNum++;
store.dispatch("setIsLoading", true);
......@@ -31,16 +45,23 @@ function clearRequest() {
}
}
//请求拦截器
// 请求拦截器
axios.interceptors.request.use(
config => {
beforeRequest();
//发起请求时,取消掉当前正在进行的相同请求
// 发起请求时,取消掉当前正在进行的相同请求
if (pending[config.url]) {
pending[config.url]("取消重复请求");
}
config.cancelToken = new CancelToken(c => (pending[config.url] = c));
// 添加token
const token = localStorage.get("mongoToken");
if (token) {
config.headers["x-auth-token"] = token;
}
return config;
},
error => {
......@@ -48,116 +69,39 @@ axios.interceptors.request.use(
}
);
//响应拦截器即异常处理
// 响应拦截器即异常处理
axios.interceptors.response.use(
response => {
afterRequest();
delete pending[response.config.url];
if (response.data.code === "0") {
return response.data;
// return response.data.data;
}
if (response.data.code === "0") return response.data.data;
Notify({ type: "danger", message: response.data.msg || "后端服务异常" });
return Promise.reject(response.data);
},
err => {
if (err && err.response) {
switch (err.response.status) {
case 400:
err.message = "错误请求";
break;
case 401:
err.message = "未授权,请重新登录";
break;
case 403:
err.message = "拒绝访问";
break;
case 404:
err.message = "请求错误,未找到该资源";
break;
case 405:
err.message = "请求方法未允许";
break;
case 408:
err.message = "请求超时";
break;
case 500:
err.message = "服务器端出错";
break;
case 501:
err.message = "网络未实现";
break;
case 502:
err.message = "网络错误";
break;
case 503:
err.message = "服务不可用";
break;
case 504:
err.message = "网络超时";
break;
case 505:
err.message = "http版本不支持该请求";
break;
default:
err.message = `连接错误${err.response.status}`;
afterRequest();
// 判断是否取消请求
if (err.message === "取消重复请求") {
const res = {
status: 409,
data: {}
};
return Promise.resolve(res);
}
} else {
if (err.message == "操作取消") {
err.response = {};
err.response.status = 409;
err.response.data = {};
return Promise.resolve(err.response);
// 错误提示
if (err.response) {
err.message = ERR_MESSAGE_MAP.status[err.response.status] || `连接错误${err.response.status}`;
} else {
err.message = "连接到服务器失败";
}
}
afterRequest();
Notify({ type: "danger", message: err.message });
return Promise.resolve(err.response);
return Promise.reject(err.response);
}
);
export default {
axios,
//get请求
get(url, params = {}) {
return new Promise((resolve, reject) => {
axios({
method: "get",
// url: url + "?" + qs.stringify(params),
url: url,
params,
headers: {
"Content-Type": "application/json",
"x-auth-token": localStorage.getItem("mongoToken") || null
}
})
.then(res => {
resolve(res);
})
.catch(e => {
reject(e);
});
});
},
//post请求
post(url, params = {}) {
return new Promise((resolve, reject) => {
axios({
method: "post",
url,
data: params,
headers: {
"Content-Type": "application/json",
"x-auth-token": localStorage.getItem("mongoToken") || null
}
})
.then(res => {
resolve(res);
})
.catch(e => {
reject(e);
});
});
}
};
export default axios;
export default {
get(key) {
let result = window.localStorage.getItem(key);
try {
return JSON.parse(result);
} catch (e) {
return result;
}
},
set(key, value) {
let toString = Object.prototype.toString;
if (toString.call(value) === "[object Array]" || toString.call(value) === "[object Object]") {
value = JSON.stringify(value);
}
return window.localStorage.setItem(key, value);
},
remove(key) {
return window.localStorage.removeItem(key);
},
clear() {
return window.localStorage.clear();
}
};
import Vue from "vue";
import Vuex from "vuex";
import user from "./modules/user";
Vue.use(Vuex);
......@@ -31,5 +32,7 @@ export default new Vuex.Store({
commit("setIsShowLogin", args);
}
},
modules: {}
modules: {
user
}
});
import GOODS_LIST from "@/api/goodsList.mock";
import { getUserInfo, getFamilyList } from "@/api/user";
import { getPolicyList } from "@/api/policy";
const CONSTANT = {
avatar: {
man: "../../../assets/images/user/man@2x.png",
woman: "../../../assets/images/user/woman@2x.png"
},
relation: ["本人", "父母", "配偶", "子女"]
};
function getReletion(relation, gender) {
let result = "";
if ([1, 3].includes(+relation)) {
if (+relation === 1) {
result = +gender ? "父亲" : "母亲";
} else {
result = +gender ? "儿子" : "女儿";
}
} else {
result = CONSTANT.relation[+relation];
}
return result;
}
export default {
namespaced: true,
state: {
familyList: [],
userInfo: {
name: "未登录",
phoneNoMask: "点击登录",
avatar: "../../assets/images/user/avatar@2x.png",
auth: false
}
},
mutations: {
setFamilyList(state, value) {
state.familyList = value;
},
setUserInfo(state, value) {
state.userInfo = value;
}
},
actions: {
async setFamilyList({ commit }) {
let familyList = await getFamilyList();
const policyList = await getPolicyList();
familyList = familyList.concat(familyList);
// todo 家人保单列表筛选
const result = familyList.map(family => ({
...family,
avatar: +family.gender === 0 ? CONSTANT.avatar.man : CONSTANT.avatar.woman,
relation: getReletion(family.relation, family.gender),
policyList: GOODS_LIST.map(goods => {
// todo 家人保单列表推荐
const filterPolicyList = policyList
.map(policy => {
const goodsChild = goods.children.find(child => child.id === +policy.productNo) || {};
return {
...policy,
...goodsChild
};
})
.filter(policy => policy.insuredUserSecId === family.userInfoSecId && policy.id)
.sort((a, b) => a.termType > b.termType);
return filterPolicyList?.[0] || goods.children[0];
})
}));
commit("setFamilyList", result);
},
async setUserInfo({ commit }) {
const userInfo = await getUserInfo();
commit("setUserInfo", userInfo);
}
}
};
......@@ -14,6 +14,9 @@ a {
color: @blue;
font-size: @font-size-12;
}
input::-webkit-input-placeholder {
color: #AAAAAA;
}
.cr-button {
padding: 0 @padding-sm !important;
&__text {
......@@ -91,7 +94,14 @@ a {
.cr-notify {
font-size: @font-size-14;
}
.table {
.cr-field--error-message {
display: none;
}
.cr-picker {
font-size: 14px;
}.table {
margin: 0;
width: 100%;
thead {
......
@import "../../../style/index.less";
.measure {
box-sizing: border-box;
min-height: 100%;
background: #EDEDED;
padding: 20px 15px;
.measure-dialogue {
margin-bottom: 20px;
&-robot {
display: flex;
.Md-robot-avatar {
margin-right: 12px;
width: 40px;
height: 40px;
}
.Md-robot-container {
padding: 14px;
width: 244px;
background: #FFFFFF;
border-radius: 0px 14px 14px 14px;
.Mdr-container-question {
margin-bottom: 4px;
font-size: 16px;
font-weight: 400;
color: #000000;
line-height: 21px;
}
.Mdr-container-progress {
font-size: 12px;
font-weight: 400;
color: #999999;
line-height: 21px;
}
.Mdr-container-component {
display: flex;
justify-content: space-between;
margin-top: 10px;
.Mdrc-component-box {
position: relative;
.Mdrcc-box-bg {
margin-top: 31px;
width: 102px;
height: 71px;
background: #F6F7F9;
border-radius: 12px;
}
.Mdrcc-box-image {
position: absolute;
bottom: 0;
width: 102px;
height: 102px;
}
}
.Mdrc-component-button {
// width: 100%;
// height: 52px;
background: #FFC842 !important;
// border-radius: 14px;
// font-size: 16px;
// font-weight: 600;
// color: #333333;
// line-height: 22px;
}
}
.Mdrc-component-marriage {
margin-top: 12px;
p {
display: flex;
align-items: center;
margin-bottom: 8px;
padding-left: 13px;
height: 32px;
background: #F6F7FA;
border-radius: 8px;
font-size: 12px;
font-weight: 400;
color: #666666;
line-height: 14px;
}
}
.Mdrc-component-income {
margin-top: 12px;
.Mdrcc-income-item {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
.Mdrcci-item_selected {
background: #FFC842;
color: #333333;
}
p {
display: flex;
align-items: center;
padding-left: 12px;
width: 105px;
height: 32px;
background: #F6F7FA;
border-radius: 8px;
font-size: 12px;
font-weight: 400;
color: #666666;
line-height: 14px;
}
}
.Mdrcc-income-jump {
display: flex;
align-items: center;
padding-left: 12px;
height: 32px;
background: #F6F7FA;
border-radius: 8px;
font-size: 12px;
font-weight: 400;
color: #666666;
line-height: 14px;
}
.Mdrcci-jump_selected {
background: #FFC842;
color: #333333;
}
}
}
}
&-operation {
display: flex;
.Md-operation-back {
display: flex;
justify-content: center;
align-items: center;
margin: 12px 0 0 52px;
width: 95px;
height: 28px;
background: #FFFFFF;
border-radius: 8px;
font-size: 14px;
font-weight: 400;
color: #666666;
line-height: 16px;
}
.Md-operation-submit {
display: flex;
justify-content: center;
align-items: center;
margin: 12px 0 0 20px;
width: 95px;
height: 28px;
background: #FFC842;
border-radius: 8px;
font-size: 14px;
font-weight: 400;
color: #333333;
line-height: 16px;
}
}
&-user {
display: flex;
justify-content: flex-end;
margin-top: 20px;
.Md-user-answer {
display: flex;
justify-content: center;
align-items: center;
margin-right: 12px;
padding: 0 14px;
height: 40px;
background: #FFC842;
border-radius: 14px 0px 14px 14px;
font-size: 16px;
font-weight: 400;
color: #333333;
line-height: 16px;
}
.Md-user-avatar {
width: 40px;
height: 40px;
}
}
}
.measure-loading {
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
margin-top: 40px;
}
}
\ No newline at end of file
<template>
<div ref="measure" class="measure">
<div class="measure-dialogue" v-for="(item, index) in smartMeasure" :key="item.id">
<div class="measure-dialogue-robot">
<cr-image
class="Md-robot-avatar"
width=""
height=""
fit="cover"
src="@/assets/images/user/avatar@2x.png"
/>
<div class="Md-robot-container">
<p class="Mdr-container-question">{{ item.question }}</p>
<p class="Mdr-container-progress">{{ item.id + "/" + dataList.length }}</p>
<component
v-if="!item.answer || index === dataList.length - 1"
:is="item.component"
:type="item.type"
@select="select"
@submit="submit"
></component>
</div>
</div>
<div class="measure-dialogue-operation">
<div
class="Md-operation-back"
v-show="index === smartMeasure.length - 1 && index !== 0"
@click="goBack(item.id)"
>
上一题
</div>
<div
class="Md-operation-submit"
@click="submit"
v-show="index === dataList.length - 1 && item.answer"
>
确认提交
</div>
</div>
<div class="measure-dialogue-user" v-show="index !== dataList.length - 1 && item.answer">
<p class="Md-user-answer">{{ item.answer }}</p>
<cr-image
class="Md-user-avatar"
width=""
height=""
fit="cover"
src="@/assets/images/user/male@2x.png"
/>
</div>
</div>
<cr-loading v-if="isLoading" class="measure-loading" size="24px">测评报告生成中...</cr-loading>
</div>
</template>
<script>
import Age from "./modules/Age";
import Gender from "./modules/Gender";
import Select from "./modules/Select";
const dataList = [
{
id: 1,
question: "请问您的性别是?",
component: "Gender",
type: "gender",
answer: ""
},
{
id: 2,
question: "请问您的年龄是?",
component: "Age",
type: "age",
answer: ""
},
{
id: 3,
question: "请问您结婚了吗?",
component: "Select",
type: "marrige",
answer: ""
},
{
id: 4,
question: "嘘…悄悄告诉我您月收入是多少?",
component: "Select",
type: "income",
answer: ""
},
{
id: 5,
question: "生活中,您有下面的习惯、环境吗",
component: "Select",
type: "environment",
answer: ""
},
{
id: 6,
question: "您平时的出行方式是什么呢?",
component: "Select",
type: "travel",
answer: ""
},
{
id: 7,
question: "您目前是否还有其他保险呢?",
component: "Select",
type: "insurance",
answer: ""
}
];
export default {
name: "SmartMeasure",
components: {
Age,
Gender,
Select
},
data() {
return {
dataList,
isLoading: false
};
},
computed: {
smartMeasure() {
let result = this.dataList.filter(data => data.answer);
if (result.length < this.dataList.length) {
result.push(this.dataList[result.length]);
}
this.scrollToBottom();
return JSON.parse(JSON.stringify(result));
}
},
methods: {
select(answer) {
const id = this.smartMeasure[this.smartMeasure.length - 1].id;
this.smartMeasure[this.smartMeasure.length - 1].answer = answer;
this.$forceUpdate();
if (this.smartMeasure.length < this.dataList.length) {
setTimeout(() => {
this.dataList = this.dataList.map(data => {
if (data.id === id) data.answer = answer;
return data;
});
}, 600);
}
},
goBack(id) {
this.dataList[id - 1].answer = "";
this.dataList[id - 2].answer = "";
},
submit() {
this.isLoading = true;
this.scrollToBottom();
setTimeout(() => {});
console.log("submit", this.dataList);
},
scrollToBottom() {
this.$nextTick(() => {
const element = document.querySelector(".measure");
document.documentElement.scrollTop = element.scrollHeight;
});
}
}
};
</script>
<style lang="less" src="./index.less" scoped></style>
<template>
<div class="Mdr-container-component">
<cr-button class="Mdrc-component-button" @click="showPicker">
选择出生年份
</cr-button>
<cr-popup v-model="showPopup" position="bottom">
<cr-picker
ref="picker"
show-toolbar
:columns="ageScope"
@confirm="onConfirm"
@cancel="showPopup = false"
/>
</cr-popup>
</div>
</template>
<script>
import male from "@/assets/images/user/male@2x.png";
import female from "@/assets/images/user/female@2x.png";
const ageScope = new Array(120)
.fill(0)
.map((v, index) => 1901 + index + "")
.sort((a, b) => (a === b ? 0 : a < b ? 1 : -1));
const dataList = [
{
image: male,
value: "male"
},
{
image: female,
value: "female"
}
];
export default {
name: "Age",
props: {},
data() {
return {
showPopup: false,
dataList,
ageScope,
refreshed: false
};
},
methods: {
showPicker() {
this.showPopup = true;
if (!this.refreshed) {
this.$refs.picker.refreshColumns();
this.refreshed = true;
}
},
onCancel() {
this.showPopup = false;
},
onConfirm(picker, res) {
this.showPopup = false;
this.$emit("select", res[0]);
}
}
};
</script>
<style lang="less" src="../index.less" scoped></style>
<template>
<div class="Mdr-container-component">
<div
class="Mdrc-component-box"
v-for="item in dataList"
:key="item.value"
@click="select(item.answer)"
>
<div class="Mdrcc-box-bg"></div>
<cr-image class="Mdrcc-box-image" width="" height="" fit="cover" :src="item.image" />
</div>
</div>
</template>
<script>
import male from "@/assets/images/user/male@2x.png";
import female from "@/assets/images/user/female@2x.png";
const dataList = [
{
image: male,
value: "male",
answer: "男神"
},
{
image: female,
value: "female",
answer: "女神"
}
];
export default {
name: "Age",
props: {},
data() {
return {
dataList
};
},
methods: {
select(value) {
this.$emit("select", value);
}
}
};
</script>
<style lang="less" src="../index.less" scoped></style>
<template>
<div class="Mdrc-component-marriage Mdrc-component-income">
<template v-if="type === 'marrige'">
<p v-for="(item, index) in answers[type].data" :key="index" @click="select(item)">
{{ item }}
</p>
</template>
<template v-else>
<div v-for="(list, index) in answers[type].data" :key="index" class="Mdrcc-income-item">
<p
:class="{ 'Mdrcci-item_selected': answers[type].selected.includes(item) }"
v-for="item in list"
:key="item"
@click="select(item, answers[type].type, type)"
>
{{ item }}
</p>
</div>
<p
v-if="!answers[type].required"
class="Mdrcc-income-jump"
:class="{ 'Mdrcci-jump_selected': answers[type].selected.includes('没有,下一题') }"
@click="select('没有,下一题', answers[type].type, type)"
>
没有,下一题
</p>
</template>
</div>
</template>
<script>
const answers = {
marrige: {
data: ["单身贵族爱自由", "幸福的二人世界", "家有儿女初长成"],
type: "radio",
selected: [],
required: true
},
income: {
data: [
["3000元以下", "3000~5000元"],
["5000~8000元", "8000~12000元"],
["12000~18000元", "18000元以上"]
],
type: "radio",
selected: [],
required: true
},
environment: {
data: [
["喝酒", "抽烟/二手烟"],
["熬夜", "不按时吃饭"],
["工作压力大", "不常运动"]
],
type: "radio",
selected: [],
required: true
},
travel: {
data: [
["开车", "公共交通"],
["非机动车", "步行"],
["坐火车", "坐飞机"]
],
tye: "radio",
selected: [],
required: false
},
insurance: {
data: [["社保", "医疗险"], ["重疾险", "意外险"], ["寿险"]],
type: "multi-select",
selected: [],
required: false
}
};
export default {
name: "Select",
props: {
type: {
type: String,
default: "marrige"
}
},
data() {
return {
answers: JSON.parse(JSON.stringify(answers))
};
},
methods: {
select(value, type, name) {
console.log(value, type, name);
if (value === "没有,下一题" && name === "insurance") {
this.answers.insurance.selected = ["没有,下一题"];
this.$emit("select", value);
this.$emit("submit");
return;
}
if (type === "multi-select") {
this.answers[name].selected = this.answers[name].selected.filter(v => v !== "没有,下一题");
this.answers[name].selected.includes(value)
? (this.answers[name].selected = this.answers[name].selected.filter(v => v !== value))
: this.answers[name].selected.push(value);
this.$emit("select", this.answers[name].selected.join(","));
} else {
this.$emit("select", value);
}
}
},
created() {
// this.answers[this.type] = answers[this.type];
console.log(answers.insurance);
}
};
</script>
<style lang="less" src="../index.less" scoped></style>
......@@ -5,7 +5,7 @@
background-color: @background-color;
&-tab {
width: 100% !important;
& > div {
@{deep} & > div {
width: 100% !important;
z-index: 100;
}
......@@ -200,7 +200,7 @@
&-button {
width: 296px;
height: 50px;
background: #FFC842;
background: #FFC842 !important;
border-radius: 14px;
z-index: 0;
&:after {
......
......@@ -9,27 +9,27 @@
<cr-tabbar-item>子女</cr-tabbar-item>
</cr-tabbar>
</cr-sticky>
<!-- <policy-item></policy-item>
<policy-item></policy-item>
<cr-divider class="policy-divider">我是有底线的</cr-divider>
<insurance-recommend></insurance-recommend> -->
<div class="policy-none">
<insurance-recommend></insurance-recommend>
<!-- <div class="policy-none">
<cr-image class="policy-none-image" round width="" height="" :src="policyDefault" />
<p class="policy-none-title">暂无保单</p>
<p class="policy-none-desc">赶紧去看看有哪些精品保险吧</p>
</div>
</div> -->
</div>
</template>
<script>
import policyDefault from "@/assets/images/policy/policy-default@2x.png";
// import InsuranceRecommend from "./modules/InsuranceRecommend";
// import PolicyItem from "./modules/PolicyItem";
import InsuranceRecommend from "./modules/InsuranceRecommend";
import PolicyItem from "./modules/PolicyItem";
export default {
name: "PolicyList",
// components: {
// InsuranceRecommend,
// PolicyItem
// },
components: {
InsuranceRecommend,
PolicyItem
},
data() {
return {
active: 0,
......
<template>
<div>
<div class="policy-item">
<div class="policy-item" v-for="item in list" :key="item.orderNo">
<div class="policy-item-pro">
<p class="policy-item-pro-name">国民保·百万医疗险</p>
<p class="policy-item-pro-type policy-item-pro-type_medical">医疗保障</p>
......@@ -16,7 +16,7 @@
width=""
height=""
fit="cover"
:src="guarantee"
src="@/assets/images/policy/guarantee@2x.png"
/>
</div>
<div class="policy-item">
......@@ -40,7 +40,7 @@
width=""
height=""
fit="cover"
:src="guarantee"
src="@/assets/images/policy/guarantee@2x.png"
/>
</div>
<div class="policy-item">
......@@ -117,14 +117,22 @@
</div>
</template>
<script>
import guarantee from "@/assets/images/policy/guarantee@2x.png";
import GOODS_LIST from "@/api/goodsList.mock";
import { getPolicyList } from "@/api/policy";
export default {
name: "InsuranceRecommend",
data() {
return {
guarantee
list: []
};
},
async created() {
const goodsList = GOODS_LIST.reduce((pre, next) => {
return pre.concat(next.children);
}, []);
let list = await getPolicyList();
this.list = list.map(v => goodsList.find(goods => goods.id === +v.productNo));
}
};
</script>
......
<template>
<div class="family">
<user-family-form type="update" title="修改信息" :information="information"></user-family-form>
</div>
</template>
<script>
import { mapState, mapActions } from "vuex";
import form from "../modules/FamilyForm";
export default {
name: "FamilyDetail",
components: {
userFamilyForm: form
},
data() {
return {
information: {
userInfoSecId: "",
nameMask: "",
idNoMask: "",
socialSecurity: "",
relation: ""
}
};
},
created() {
const information = this.familyList.find(
family => family.userInfoSecId === this.$route.params.id
);
this.information = {
...information,
socialSecurity: information.socialSecurity ? "true" : "false"
};
},
computed: {
...mapState("user", ["familyList"])
},
methods: {
...mapActions("user", ["setFamilyList"])
}
};
</script>
<style lang="less" src="../index.less" scoped></style>
......@@ -14,6 +14,93 @@
line-height: 24px;
}
&-list {
border:1px solid transparent;
margin: 16px 0 0;
&-item {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
padding: 0 20px;
height: 66px;
background: #FFFFFF;
border-radius: 14px;
.Fl-item-left {
display: flex;
align-items: center;
.Fli-left-image {
margin-right: 12px;
width: 40px;
height: 40px;
}
.Fli-left-name {
margin-right: 10px;
font-size: 16px;
font-weight: 600;
color: #333333;
line-height: 16px;
}
.Fli-left-relation {
font-size: 11px;
font-weight: 400;
color: #999999;
line-height: 16px;
}
}
.Fl-item-right {
width: 44px;
height: 16px;
background: #FFEAB7;
border-radius: 2px 8px 2px 8px;
text-align: center;
font-size: 11px;
font-weight: 400;
color: #EAAD1A;
line-height: 16px;
}
&_overlay {
border-radius: 17px;
margin-top: 35px;
box-shadow: 0px -5px 25px 0px rgba(0,0,0,0.07), 0px -20px 0 -10px #FFFFFF, 0px -25px 25px 0px rgba(0,0,0,0.07), 0px -33px 0 -14px #FFFFFF;
}
}
}
&-collapse {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 20px;
height: 30px;
background: #FFFFFF;
border-radius: 14px;
&-text {
margin-right: 4px;
font-size: 12px;
font-weight: 500;
color: #858AFF;
line-height: 17px;
}
&-svg {
transform: rotate(0deg);
width: 16px;
height: 16px;
&_opened {
transform: rotate(180deg);
}
}
}
&-form {
padding: 20px 20px 28px;
background: #FFFFFF;
......@@ -80,10 +167,13 @@
overflow: visible;
padding: 0;
width: auto;
@{deep} .cr-cell__value {
overflow: visible;
.cr-radio-group {
margin: 0;
.cr-radio {
// display: inline-block;
// box-sizing: border-box;
......@@ -97,6 +187,7 @@
.cr-radio__label--right {
font-size: 0;
div {
font-size: 12px;
font-weight: 400;
......@@ -110,6 +201,7 @@
}
}
}
.Ffr-options-text {
display: inline-block;
padding: 12px 0;
......@@ -140,8 +232,13 @@
font-weight: 600;
color: #333333;
line-height: 22px;
&_deleted {
margin-top: 15px;
background: #F6F7FA !important;
}
}
}
&-modal {
@{deep} .panel-body {
font-size: 16px;
......@@ -150,21 +247,26 @@
line-height: 28px;
}
}
&-confirm-modal {
padding: 20px 17px;
background: #F6F7FA;
border-radius: 8px;
.Fc-modal-item {
display: flex;
justify-content: space-between;
font-size:12px;
// justify-content: space-between;
font-size: 12px;
color: #333333;
line-height: 30px;
span:nth-child(1) {
font-weight:400;
width: 65px;
font-weight: 400;
}
span:nth-child(2) {
font-weight:600;
font-weight: 600;
}
}
}
......
<template>
<div class="family">
<p class="family-title">为家人添加保障</p>
<div v-if="familyList.length">
<p class="family-title">已添加家人</p>
<div class="family-list" v-if="!isCollapse">
<div
:class="[{ 'family-list-item_overlay': isCollapse && index === 0 }, 'family-list-item']"
v-for="(item, index) in familyList"
@click="go(`/user/family/detail/${item.userInfoSecId}`)"
:key="index"
>
<div class="Fl-item-left">
<cr-image class="Fli-left-image" :src="item.avatar" width="" height="" />
<span class="Fli-left-name">{{ item.name }}</span>
<span class="Fli-left-relation">{{ item.relation }}</span>
</div>
<p class="Fl-item-right" v-if="item.auth">已认证</p>
</div>
</div>
<div class="family-list" v-else>
<div
class="family-list-item_overlay family-list-item"
@click="go(`/user/family/detail/${familyList[0].userInfoSecId}`)"
>
<div class="Fl-item-left">
<cr-image class="Fli-left-image" :src="familyList[0].avatar" width="" height="" />
<span class="Fli-left-name">{{ familyList[0].name }}</span>
<span class="Fli-left-relation">{{ familyList[0].relation }}</span>
</div>
<p class="Fl-item-right" v-if="familyList[0].auth">已认证</p>
</div>
</div>
<div class="family-collapse" @click="isCollapse = !isCollapse">
<span class="family-collapse-text">{{ collapseText }}</span>
<svg-icon
icon-class="triangle-down"
:class-name="[{ 'family-collapse-svg_opened': !isCollapse }, 'family-collapse-svg']"
/>
</div>
</div>
<user-family-form type="add" title="为家人添加保障"></user-family-form>
<!-- <p class="family-title">为家人添加保障</p>
<cr-form ref="form" class="family-form" @submit="onSubmit" @failed="onFailed">
<cr-field
class="family-form-item"
v-model="formData.username"
v-model="formData.name"
name="姓名"
label="姓名"
placeholder="请输入投保人姓名"
......@@ -12,11 +51,12 @@
/>
<cr-field
class="family-form-item"
v-model="formData.idcard"
v-model="formData.idNo"
type="password"
name="身份证号"
label="身份证号"
placeholder="请填写家人身份证号"
:rules="[{ required: true, message: '请填写身份证号' }]"
/>
<cr-field
@click.native="showPopups"
......@@ -26,6 +66,7 @@
name="与本人的关系"
label="与本人的关系"
placeholder="请选择与本人的关系"
:rules="[{ required: true, message: '请选择与本人的关系' }]"
/>
<div class="family-form-radio">
<div class="Ff-radio-title">
......@@ -39,7 +80,7 @@
<cr-field
class="Ff-radio-options"
name="社保"
:rules="[{ required: true, message: '请填写用户名' }]"
:rules="[{ required: true, message: '请选择有无社保' }]"
>
<cr-radio-btn
class=""
......@@ -52,104 +93,34 @@
<cr-button class="family-form-button" native-type="submit">
生成保障方案
</cr-button>
</cr-form>
<cr-popup v-model="showPopup" position="bottom">
<cr-picker
ref="picker"
show-toolbar
:columns="relations"
@confirm="onConfirm"
@cancel="showPopup = false"
/>
</cr-popup>
<Modal
class="family-modal"
v-model="modal.question"
:closeable="false"
cancel-btn=""
title="我们常说的社保都包括哪些?"
confirm-btn="我知道了"
>
常见的社保包括农村合作医疗(新农合)、城镇居民社保、城镇职工医保、少儿医保等政府主导的基本医疗保障项目,满足最基本的医疗保障要求。
</Modal>
<Modal
v-model="modal.confirm"
:closeable="false"
cancel-btn="取消"
confirm-btn="确认无误"
title="信息确认"
>
<div class="family-confirm-modal">
<div class="Fc-modal-item">
<span>首月保费</span>
<span>1元</span>
</div>
<div class="Fc-modal-item">
<span>次月保费</span>
<span>100.00元/月 (共11期)</span>
</div>
<div class="Fc-modal-item">
<span>次月保费</span>
<span>100.00元/月 (共11期)</span>
</div>
<div class="Fc-modal-item">
<span>次月保费</span>
<span>100.00元/月 (共11期)</span>
</div>
</div>
</Modal>
<Modal
class="family-modal"
v-model="modal.delete"
:closeable="false"
cancel-btn="确认删除"
confirm-btn="继续保留"
title="删除确认"
>确认删除【王大闹】的个人信息吗?为提供全面的家庭保障,建议您保留家庭成员信息。
</Modal>
</cr-form> -->
</div>
</template>
<script>
import CrRadioBtn from "@/components/CrRadioBtn";
import Modal from "@/components/Modal";
const planOptions = [
{ label: "有社保", value: "1" },
{ label: "无社保", value: "2" }
];
const relations = ["本人", "配偶", "父母", "子女"];
import { mapState, mapActions } from "vuex";
import form from "./modules/FamilyForm";
export default {
name: "Family",
components: {
CrRadioBtn,
Modal
userFamilyForm: form
},
data() {
return {
showPopup: false,
relations,
planOptions,
modal: {
question: false,
confirm: false,
delete: false
},
formData: {
username: "",
idcard: "",
relation: "",
socialSecurity: ""
}
isCollapse: true
};
},
methods: {
async onSubmit() {
// console.log('sucess', values);
computed: {
...mapState("user", ["familyList"]),
collapseText() {
return this.isCollapse ? "点击展开" : "点击收起";
}
},
onFailed() {
// console.log('fail', errorInfo);
created() {
this.setFamilyList();
},
methods: {
...mapActions("user", ["setFamilyList"]),
onConfirm(picker, res) {
this.formData.relation = res[0];
this.showPopup = false;
......@@ -160,6 +131,10 @@ export default {
this.$refs.picker.refreshColumns();
this.refreshed = true;
}
},
go(path) {
console.log(path);
this.$router.push(path);
}
}
};
......
<template>
<div class="user-family">
<p class="family-title">{{ title }}</p>
<cr-form ref="form" class="family-form" @submit="modal.confirm = true" @failed="onFailed">
<cr-field
class="family-form-item"
v-model="formData.nameMask"
:readonly="readOnlyProperty.nameMask"
name="姓名"
label="姓名"
placeholder="请输入投保人姓名"
:rules="[{ required: true, message: '请填写用户名' }]"
/>
<cr-field
class="family-form-item"
v-model="formData.idNoMask"
:readonly="readOnlyProperty.idNoMask"
type="password"
name="身份证号"
label="身份证号"
placeholder="请填写家人身份证号"
:rules="[{ required: true, message: '请填写身份证号' }]"
/>
<cr-field
@click.native="showPopups"
class="family-form-item"
v-model="formData.relation"
:readonly="true"
name="与本人的关系"
label="与本人的关系"
placeholder="请选择与本人的关系"
:rules="[{ required: true, message: '请选择与本人的关系' }]"
/>
<div class="family-form-radio">
<div class="Ff-radio-title">
<span class="Ffr-title-text">有无社保</span>
<svg-icon
icon-class="doubt"
@click.native="modal.question = true"
class-name="Ffr-title-svg"
/>
</div>
<cr-field class="Ff-radio-options" name="社保">
<cr-radio-btn slot="input" v-model="formData.socialSecurity" :radio-data="planOptions" />
</cr-field>
</div>
<cr-button class="family-form-button" native-type="submit">
{{ saveText }}
</cr-button>
<cr-button class="family-form-button_deleted" @click="modal.delete = true" v-if="isShowDel">
删除成员
</cr-button>
</cr-form>
<Modal
class="family-modal"
v-model="modal.question"
:closeable="false"
@cancel="modal.question = false"
cancel-btn=""
title="我们常说的社保都包括哪些?"
confirm-btn="我知道了"
>
常见的社保包括农村合作医疗(新农合)、城镇居民社保、城镇职工医保、少儿医保等政府主导的基本医疗保障项目,满足最基本的医疗保障要求。
</Modal>
<Modal
v-model="modal.confirm"
:closeable="false"
@confirm="onSubmit"
@cancel="modal.confirm = false"
cancel-btn="取消"
confirm-btn="确认无误"
title="信息确认"
>
<div class="family-confirm-modal">
<div class="Fc-modal-item">
<span v-html="'姓&#12288;&#12288;名:'"></span>
<span>{{ formData.nameMask }}</span>
</div>
<div class="Fc-modal-item">
<span>身份证号:</span>
<span>{{ formData.idNoMask }}</span>
</div>
<div class="Fc-modal-item">
<span>与您关系:</span>
<span>{{ formData.relation }}</span>
</div>
<div class="Fc-modal-item">
<span>有无社保:</span>
<span>{{ formData.socialSecurity === "true" ? "有社保" : "无社保" }}</span>
</div>
</div>
</Modal>
<Modal
class="family-modal"
v-model="modal.delete"
@confirm="modal.delete = false"
@cancel="delFamily"
:closeable="false"
cancel-btn="确认删除"
confirm-btn="继续保留"
title="删除确认"
>确认删除【王大闹】的个人信息吗?为提供全面的家庭保障,建议您保留家庭成员信息。
</Modal>
<cr-popup v-model="showPopup" position="bottom">
<cr-picker
ref="picker"
show-toolbar
:columns="relations"
@confirm="onConfirm"
@cancel="showPopup = false"
/>
</cr-popup>
</div>
</template>
<script>
import { mapState, mapActions } from "vuex";
import formValidMixin from "@/mixins/formValidate.mixin";
import { addFamily, updateFamily, delFamily } from "@/api/user";
import CrRadioBtn from "@/components/CrRadioBtn";
import Modal from "@/components/Modal";
const relations = ["本人", "配偶", "父母", "子女"];
const planOptions = [
{ label: "有社保", value: "true" },
{ label: "无社保", value: "false" }
];
export default {
name: "FamilyForm",
components: {
CrRadioBtn,
Modal
},
mixins: [formValidMixin],
props: {
title: {
type: String,
default: "为家人添加保障"
},
type: {
type: String,
default: "add"
},
information: {
type: Object,
default: () => ({})
}
},
data() {
return {
showPopup: false,
relations,
planOptions,
modal: {
question: false,
confirm: false,
delete: false
},
formData: this.information,
isCollapse: true
};
},
computed: {
...mapState("user", ["familyList"]),
readOnlyProperty() {
if (this.type === "add") return {};
let result = { relation: true };
if (this.formData?.relation === "本人") {
result = {
...result,
...{
nameMask: true,
idNoMask: true
}
};
}
return result;
},
saveText() {
return this.type === "add" ? "生成保障方案" : "保存修改";
},
isShowDel() {
return this.type === "update" && this.formData.relation !== "本人" ? true : false;
}
},
created() {
console.log(this.formData);
},
methods: {
...mapActions("user", ["setFamilyList"]),
async onSubmit() {
this.modal.confirm = false;
// 组件不支持boolean,需转换
const params = {
...this.formData,
socialSecurity: this.formData?.socialSecurity === "true" ? true : false
};
if (this.type === "add") {
await addFamily(params);
} else {
await updateFamily(params);
}
},
onConfirm(picker, res) {
this.formData.relation = res[0];
this.showPopup = false;
},
showPopups() {
if (this.readOnlyProperty.relation) return;
this.showPopup = true;
if (!this.refreshed) {
this.$refs.picker.refreshColumns();
this.refreshed = true;
}
},
async delFamily() {
this.modal.delete = false;
await delFamily();
this.$router.push("/user/family");
}
}
};
</script>
<style lang="less" src="../index.less" scoped></style>
......@@ -19,7 +19,7 @@
color: @black;
}
span:nth-child(2) {
width: 63px;
width: 89px;
padding: 1px 0 2px;
line-height: normal;
text-align: center;
......@@ -117,6 +117,9 @@
&:not(:first-child) {
margin-left: 25px;
}
&_placeholder {
margin-right: 65px;
}
&-svg {
width: 40px;
height: 40px;
......@@ -137,7 +140,7 @@
border-radius: 3px;
}
&_fixed {
position: fixed;
position: absolute;
right: 36px;
height: 71px;
background: #fff;
......
......@@ -2,8 +2,8 @@
<div class="user">
<div class="user-info">
<div class="user-info-account" @click="go('', true)">
<span>未登录</span>
<span>点击登录</span>
<span>{{ userInfo.name }}</span>
<span>{{ userInfo.phoneNoMask }}</span>
</div>
<div class="user-info-image" @click="go('', true)">
<cr-image
......@@ -12,9 +12,13 @@
height=""
round
fit="cover"
src="@/assets/images/user/avatar@2x.png"
:src="userInfo.avatar"
/>
<svg-icon
v-if="userInfo.auth"
icon-class="certification"
class-name="user-info-image-certification"
/>
<!-- <svg-icon icon-class="certification" class-name="user-info-image-certification" /> -->
</div>
</div>
<div class="user-insurance">
......@@ -55,6 +59,7 @@
</div>
</template>
<script>
import { mapState, mapActions } from "vuex";
import customerService from "@/assets/images/user/customer-service@2x.png";
import help from "@/assets/images/user/help@2x.png";
import avatar from "@/assets/images/user/avatar@2x.png";
......@@ -78,7 +83,16 @@ export default {
showLayer: false
};
},
computed: {
...mapState("user", ["familyList", "userInfo"])
},
async created() {
await this.setUserInfo();
await this.setFamilyList();
console.log(this.familyList, this.userInfo);
},
methods: {
...mapActions("user", ["setFamilyList", "setUserInfo"]),
go(path, isOverlay = false) {
if (isOverlay) {
this.showLayer = true;
......
<template>
<div class="user-family">
<p class="user-family-title">家庭配置保障</p>
<div class="user-family-info">
<!-- <div class="user-family-info-item">
<div class="user-family-info" :class="{ 'user-family-info-item_placeholder': isFixed }">
<div
class="user-family-info-item"
@click="activeIndex = index"
v-for="(item, index) in familyList"
:key="item.id"
>
<cr-image
round
width="40px"
......@@ -11,35 +16,42 @@
src="http://desk.fd.zol-img.com.cn/g5/M00/00/07/ChMkJ1ZqMb2IWITEAAbRDaofaNIAAGBHwO3hh0ABtEl380.jpg"
/>
<span class="user-family-info-item-name">王斌</span>
<div class="user-family-info-item-divider"></div>
</div>-->
<div class="user-family-info-item-divider" v-show="index === activeIndex"></div>
</div>
<div
class="user-family-info-item"
:class="{ 'user-family-info-item_fixed': isFixed }"
@click="go"
@click="go('/user/family')"
>
<svg-icon icon-class="add-family" class-name="user-family-info-item-svg" />
<span class="user-family-info-item-name">添加</span>
</div>
</div>
<div class="user-family-insurance" @click="go">
<div class="user-family-insurance-item">
<cr-image round width="" height="" class="user-family-insurance-item-left" :src="medical" />
<div class="user-family-insurance">
<!-- user-family-insurance-item-middle_enable 保障中 -->
<div class="user-family-insurance-item" v-for="item in policyList" :key="item.id">
<cr-image
round
width=""
height=""
class="user-family-insurance-item-left"
:src="item.productNo ? item.icon : item.icon_closed"
/>
<div class="user-family-insurance-item-middle">
<div class="Ufii-middle-main">
<span class="Ufii-middle-main-title">医疗保障</span>
<!-- <span class="status">保障中</span> -->
<span class="Ufii-middle-main-title">{{ item.guarantee_title }}</span>
<span class="Ufii-middle-main-status" v-if="item.productNo">保障中</span>
</div>
<div class="Ufii-middle-footer">看病报销医药费,最高600万</div>
<div class="Ufii-middle-footer">{{ item.guarantee_sub }}</div>
</div>
<p class="user-family-insurance-item-right">开启保障</p>
<p class="user-family-insurance-item-right" v-if="!item.productNo">开启保障</p>
</div>
<div class="user-family-insurance-item">
<!-- <div class="user-family-insurance-item">
<cr-image round width="" height="" class="user-family-insurance-item-left" :src="illness" />
<div class="user-family-insurance-item-middle">
<div class="Ufii-middle-main">
<span class="Ufii-middle-main-title">重疾保障</span>
<!-- <span class="status">保障中</span> -->
<span class="status">保障中</span>
</div>
<div class="Ufii-middle-footer">100种重症+40种轻症</div>
</div>
......@@ -53,11 +65,10 @@
class="user-family-insurance-item-left"
:src="casualty"
/>
<!-- user-family-insurance-item-middle_enable 保障中 -->
<div class="user-family-insurance-item-middle">
<div class="Ufii-middle-main">
<span class="Ufii-middle-main-title">意外保障</span>
<!-- <span class="Ufii-middle-main-status">保障中</span> -->
<span class="Ufii-middle-main-status">保障中</span>
</div>
<div class="Ufii-middle-footer">意外风险覆盖全,最高100万保额</div>
</div>
......@@ -68,44 +79,49 @@
<div class="user-family-insurance-item-middle">
<div class="Ufii-middle-main">
<span class="Ufii-middle-main-title">人寿保障</span>
<!-- <span class="status">保障中</span> -->
<span class="status">保障中</span>
</div>
<div class="Ufii-middle-footer">最高350万保额,顶梁柱必备</div>
</div>
<p class="user-family-insurance-item-right">开启保障</p>
</div>
</div> -->
</div>
</div>
</template>
<script>
import medical from "@/assets/images/user/medical_closed@2x.png";
import casualty from "@/assets/images/user/casualty_closed@2x.png";
import illness from "@/assets/images/user/illness_closed@2x.png";
import life from "@/assets/images/user/life_closed@2x.png";
import { mapState } from "vuex";
export default {
name: "UserFamily",
data() {
return {
medical,
casualty,
illness,
life,
isFixed: false
isFixed: false,
activeIndex: 0
};
},
methods: {
go() {
this.$emit("go", "", true);
computed: {
...mapState("user", ["familyList"]),
policyList() {
// console.log(this.activeIndex, this.familyList[this.activeIndex]?.policyList);
return this.familyList[this.activeIndex]?.policyList;
}
},
mounted() {
watch: {
familyList() {
this.$nextTick(() => {
console.log(this.familyList.length);
const offsetWidth = document.querySelector(".user-family-info").offsetWidth;
const scrollWidth = document.querySelector(".user-family-info").scrollWidth;
this.isFixed = scrollWidth > offsetWidth;
console.log(scrollWidth, offsetWidth, this.isFixed);
});
}
},
methods: {
go(path) {
this.$emit("go", path);
}
}
};
</script>
<style lang="less" src="../index.less" scoped></style>
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