Commit afcbe3a4 authored by chenqikuai's avatar chenqikuai

vue2-》vue3

parent c05acccb
module.exports = { module.exports = {
presets: [ presets: [
'@vue/cli-plugin-babel/preset' '@vue/cli-plugin-babel/preset'
],
"plugins": [
[
"import",
{
"libraryName": "vant",
"libraryDirectory": "es",
"style": true
}
]
] ]
} }
This diff is collapsed.
...@@ -7,7 +7,9 @@ ...@@ -7,7 +7,9 @@
"build": "vue-cli-service build" "build": "vue-cli-service build"
}, },
"dependencies": { "dependencies": {
"axios": "^0.21.1",
"core-js": "^3.6.5", "core-js": "^3.6.5",
"vant": "^3.2.0",
"vue": "^3.0.0", "vue": "^3.0.0",
"vue-router": "^4.0.0-0", "vue-router": "^4.0.0-0",
"vuex": "^4.0.0-0" "vuex": "^4.0.0-0"
...@@ -16,11 +18,17 @@ ...@@ -16,11 +18,17 @@
"@vue/cli-plugin-babel": "~4.5.0", "@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0", "@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-plugin-typescript": "~4.5.0", "@vue/cli-plugin-typescript": "~4.5.0",
"babel-plugin-import": "^1.13.3",
"@vue/cli-plugin-vuex": "~4.5.0", "@vue/cli-plugin-vuex": "~4.5.0",
"@vue/cli-service": "~4.5.0", "@vue/cli-service": "~4.5.0",
"@vue/compiler-sfc": "^3.0.0", "@vue/compiler-sfc": "^3.0.0",
"less": "^3.0.4", "less": "^3.0.4",
"less-loader": "^5.0.0", "less-loader": "^5.0.0",
"typescript": "~4.1.5" "typescript": "~4.1.5",
"autoprefixer": "^9.8.6",
"postcss-px-to-viewport-opt": "0.0.4",
"postcss-viewport-units": "^0.1.6",
"postcss": "^7.0.36",
"tailwindcss": "npm:@tailwindcss/postcss7-compat@^2.2.7"
} }
} }
// postcss.config.js
module.exports = {
plugins: {
"postcss-px-to-viewport-opt": {
"viewportWidth": 375, // 视窗的宽度,对应的是我们设计稿的宽度,一般是750
"viewportHeight": 1336, // 视窗的高度,根据750设备的宽度来指定,一般指定1334,也可以不配置
"unitPrecision": 3, // 指定`px`转换为视窗单位值的小数位数(很多时候无法整除)
"viewportUnit": "vw", // 指定需要转换成的视窗单位,建议使用vw
"selectorBlackList": [".ignore", ".hairlines"], // 指定不转换为视窗单位的类,可以自定义,可以无限添加,建议定义一至两个通用的类名
"minPixelValue": 2, // 小于或等于`1px`不转换为视窗单位,你也可以设置为你想要的值
"mediaQuery": false, // 允许在媒体查询中转换`px`
"exclude": /(\/|\\)(node_modules)(\/|\\)/
},
"postcss-viewport-units": {
filterRule: rule => rule.nodes.findIndex(i => i.prop === 'content') === -1
},
tailwindcss: {},
autoprefixer: {},
}
}
\ No newline at end of file
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript> </noscript>
<div id="app"></div> <div id="app"></div>
<script
src="https://at.alicdn.com/t/font_2711356_80n431prnyh.js?spm=a313x.7781069.1998910419.63&file=font_2711356_80n431prnyh.js"></script>
<!-- built files will be auto injected --> <!-- built files will be auto injected -->
</body> </body>
</html> </html>
<template> <template>
<div id="nav"> <div id="nav">
<router-link to="/">Home</router-link> | <router-view />
<router-link to="/about">About</router-link>
</div> </div>
<router-view/>
</template> </template>
<style lang="less"> <style lang="less">
#app { .fade-enter-active,
font-family: Avenir, Helvetica, Arial, sans-serif; .fade-leave-active {
-webkit-font-smoothing: antialiased; transition: opacity 0.5s;
-moz-osx-font-smoothing: grayscale; }
text-align: center; .fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
color: #2c3e50; opacity: 0;
}
/* 可以设置不同的进入和离开动画 */
/* 设置持续时间和动画函数 */
.slide-fade-enter-active {
transition: all 0.3s ease;
}
.slide-fade-leave-active {
transition: all 0.8s cubic-bezier(1, 0.5, 0.8, 1);
}
.slide-fade-enter, .slide-fade-leave-to
/* .slide-fade-leave-active for below version 2.1.8 */ {
transform: translateX(10px);
opacity: 0;
} }
#nav { .flex-col {
padding: 30px; display: flex;
flex-direction: column;
a { }
font-weight: bold; .flex-row {
color: #2c3e50; display: flex;
flex-direction: row;
&.router-link-exact-active {
color: #42b983;
}
}
} }
</style> </style>
This diff is collapsed.
<template>
</template>
<script lang="ts">
import Vue from 'vue'
export default defineComponent({
})
</script>
\ No newline at end of file
<template>
<div class="main4 flex-col">
<div class="bd3 flex-col">
<span class="info4">建信现金添益A</span>
<div class="section1 flex-row">
<div class="bd4 flex-col"><span class="info5">活期爆款</span></div>
<div class="bd5 flex-col"><span class="info6">存取灵活</span></div>
<div class="bd6 flex-col"><span class="word14">中底风险</span></div>
</div>
<span class="info7">2.73%</span>
<span class="txt8">预计年化收益</span>
<button class="section2 flex-col">
<span class="word15">立即查看</span>
</button>
</div>
</div>
</template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
export default defineComponent({});
</script>
<style lang="less" scoped>
.main4 {
z-index: 5;
height: 231px;
border-radius: 20px;
background: linear-gradient(180deg, #c6d4f6 0%, #ffffff 100%);
box-shadow: 0px 2px 3px 0px rgba(255, 255, 255, 0.5);
width: 335px;
justify-content: center;
align-items: center;
.bd3 {
z-index: auto;
width: 275px;
height: 191px;
.info4 {
z-index: 21;
width: 107px;
display: block;
overflow-wrap: break-word;
color: rgba(27, 31, 55, 1);
font-size: 16px;
font-family: PingFangSC-Semibold;
white-space: nowrap;
line-height: 22px;
text-align: center;
align-self: center;
}
.section1 {
z-index: auto;
width: 220px;
height: 20px;
justify-content: space-between;
margin: 15px 0 0 28px;
.bd4 {
z-index: 13;
height: 20px;
border-radius: 5px;
background-color: rgba(211, 221, 244, 1);
width: 70px;
justify-content: center;
align-items: center;
.info5 {
z-index: 14;
width: 48px;
display: block;
overflow-wrap: break-word;
color: rgba(62, 79, 175, 1);
font-size: 12px;
white-space: nowrap;
line-height: 17px;
text-align: center;
}
}
.bd5 {
z-index: 15;
height: 20px;
border-radius: 5px;
background-color: rgba(211, 221, 244, 1);
width: 70px;
justify-content: center;
align-items: center;
.info6 {
z-index: 16;
width: 48px;
display: block;
overflow-wrap: break-word;
color: rgba(62, 79, 175, 1);
font-size: 12px;
white-space: nowrap;
line-height: 17px;
text-align: center;
}
}
.bd6 {
z-index: 17;
height: 20px;
border-radius: 5px;
background-color: rgba(211, 221, 244, 1);
width: 70px;
justify-content: center;
align-items: center;
.word14 {
z-index: 18;
width: 48px;
display: block;
overflow-wrap: break-word;
color: rgba(62, 79, 175, 1);
font-size: 12px;
white-space: nowrap;
line-height: 17px;
text-align: center;
}
}
}
.info7 {
z-index: 19;
width: 91px;
display: block;
overflow-wrap: break-word;
color: rgba(240, 58, 48, 1);
font-size: 30px;
font-family: PingFangHK-Semibold;
white-space: nowrap;
line-height: 42px;
text-align: center;
align-self: flex-end;
margin: 16px 87px 0 0;
}
.txt8 {
z-index: 20;
width: 72px;
display: block;
overflow-wrap: break-word;
color: rgba(141, 146, 175, 1);
font-size: 12px;
white-space: nowrap;
line-height: 17px;
text-align: center;
align-self: center;
margin-top: 9px;
}
.section2 {
z-index: 11;
height: 40px;
border-radius: 20px;
background-color: rgba(62, 79, 175, 1);
margin-top: 10px;
width: 275px;
justify-content: center;
align-items: center;
.word15 {
z-index: 12;
width: 64px;
display: block;
overflow-wrap: break-word;
color: rgba(255, 255, 255, 1);
font-size: 16px;
font-family: PingFangSC-Semibold;
white-space: nowrap;
line-height: 22px;
text-align: center;
}
}
}
}
</style>
\ No newline at end of file
<template>
<div class="outer5 flex-row relative">
<div class="main2 flex-col">
<div class="bd2 flex-row">
<div class="layer1 flex-col">
<span class="txt5 overflow-hidden overflow-ellipsis">3.10%</span>
<span class="word8 overflow-hidden overflow-ellipsis"
>七日年化收益</span
>
</div>
<div class="layer2 flex-col"></div>
<div class="layer3 flex-col">
<span class="txt6 overflow-hidden overflow-ellipsis"
>乾元-sdfsdfsdfsdfsdfsdfsdf</span
>
<div class="word9 overflow-hidden overflow-ellipsis">
货币市场基金
</div>
<span class="txt7 overflow-hidden overflow-ellipsis"
>万分收益&nbsp;0.7357</span
>
</div>
</div>
</div>
<div class="orange flex items-center justify-center">
<div class="word16">推荐</div>
</div>
<div class="triangle-orange"></div>
<!-- <div class="blue flex items-center justify-center">
<div class="word16">新发</div>
</div>
<div class="triangle-blue"></div> -->
</div>
</template>
<style lang="less" scoped>
.triangle-orange {
position: absolute;
z-index: 99;
right: 0;
width: 0px;
height: 0px;
border-top: 4px solid #9e5906;
border-bottom: 4px solid transparent;
border-left: 3px solid #9e5906;
border-right: 3px solid transparent;
margin-top: 41px;
}
.triangle-blue {
position: absolute;
z-index: 99;
right: 0;
width: 0px;
height: 0px;
border-top: 4px solid #283fa0;
border-bottom: 4px solid transparent;
border-left: 3px solid #283fa0;
border-right: 3px solid transparent;
margin-top: 41px;
}
.outer5 {
z-index: auto;
width: 343px;
height: 114px;
justify-content: space-between;
margin: 10px 0 0 20px;
.main2 {
z-index: 58;
height: 114px;
border-radius: 20px;
border-width: 1px;
border: 1px solid rgba(255, 255, 255, 1);
background-color: rgba(255, 255, 255, 1);
width: 335px;
justify-content: flex-end;
align-items: flex-start;
padding: 0 0 16px 20px;
.bd2 {
z-index: auto;
width: 260px;
height: 78px;
justify-content: space-between;
.layer1 {
z-index: auto;
width: 73px;
height: 50px;
margin-top: 15px;
.txt5 {
z-index: 63;
width: 58px;
display: block;
overflow-wrap: break-word;
color: rgba(240, 58, 48, 1);
font-size: 20px;
font-family: PingFangHK-Semibold;
white-space: nowrap;
line-height: 28px;
text-align: center;
align-self: flex-start;
margin-left: 4px;
}
.word8 {
z-index: 67;
width: 73px;
display: block;
overflow-wrap: break-word;
color: rgba(141, 146, 175, 1);
font-size: 12px;
letter-spacing: 0.14399999380111694px;
font-family: PingFangHK-Regular;
white-space: nowrap;
line-height: 17px;
text-align: center;
margin-top: 5px;
}
}
.layer2 {
z-index: 68;
width: 1px;
height: 78px;
border: 1px solid #eaf0ff;
}
.layer3 {
z-index: auto;
width: 167px;
height: 74px;
.txt6 {
z-index: 64;
width: 167px;
display: block;
overflow-wrap: break-word;
color: rgba(27, 31, 55, 1);
font-size: 16px;
letter-spacing: 0.19200000166893005px;
font-family: PingFangHK-Semibold;
white-space: nowrap;
line-height: 22px;
text-align: center;
}
.word9 {
z-index: 65;
display: block;
overflow-wrap: break-word;
color: rgba(27, 31, 55, 1);
font-size: 14px;
letter-spacing: 0.1679999977350235px;
font-family: PingFangHK-Regular;
white-space: nowrap;
line-height: 20px;
text-align: center;
align-self: flex-start;
margin-top: 5px;
}
.txt7 {
z-index: 66;
display: block;
overflow-wrap: break-word;
color: rgba(141, 146, 175, 1);
font-size: 12px;
letter-spacing: 0.14399999380111694px;
font-family: PingFangHK-Regular;
white-space: nowrap;
line-height: 17px;
text-align: center;
align-self: flex-start;
margin-top: 10px;
}
}
}
}
}
.orange {
position: absolute;
z-index: 70;
top: 11px;
right: 0;
width: 56px;
height: 30px;
border-radius: 15px 0 0 15px;
background-color: rgba(255, 145, 13, 1);
}
.blue {
position: absolute;
z-index: 70;
top: 11px;
right: 0;
width: 56px;
height: 30px;
border-radius: 15px 0 0 15px;
background-color: #3555dc;
}
.main6 {
z-index: 60;
left: 306px;
top: 579px;
width: 56px;
height: 30px;
border-radius: 15px 0 0 15px;
background-color: rgba(53, 85, 220, 1);
}
.word16 {
overflow-wrap: break-word;
color: rgba(255, 255, 255, 1);
font-size: 14px;
letter-spacing: 0.1679999977350235px;
font-family: PingFangHK-Medium;
white-space: nowrap;
text-align: center;
}
</style>
\ No newline at end of file
<template>
<div class="wrap12 flex mx-5 items-center">
<span class="word8">{{ title }}</span>
<span v-if="subtitle" class="ml-3 info2">{{ subtitle }}</span>
<div class="flex-grow"></div>
<span class="word9" v-if="iconName === 'icon-gengduo'">更多</span>
<icon
v-if="iconName === 'icon-gengduo'"
name="icon-gengduo"
color="#979BB6"
size="10"
/>
<icon
v-else-if="iconName === 'icon-shaixuan'"
:name="iconName"
color="#979BB6"
size="16"
@click="clickFilter"
/>
<icon v-else :name="iconName" color="#979BB6" size="16" />
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import Icon from "../common/Icon.vue";
export default defineComponent({
emits: ["filter"],
components: { Icon },
props: {
title: {
type: String,
},
subtitle: {
type: String,
},
iconName: {
type: String,
default: "icon-gengduo",
},
},
methods: {
clickFilter() {
this.$emit("filter");
},
},
});
</script>
<style scoped>
.word8 {
overflow-wrap: break-word;
color: rgba(27, 31, 55, 1);
font-size: 16px;
letter-spacing: 0.19200000166893005px;
font-family: PingFangSC-Medium;
white-space: nowrap;
text-align: center;
}
.word9 {
display: block;
overflow-wrap: break-word;
color: rgba(27, 31, 55, 1);
font-size: 12px;
letter-spacing: 0.14399999380111694px;
white-space: nowrap;
text-align: left;
}
.info2 {
z-index: 80;
width: 102px;
display: block;
overflow-wrap: break-word;
color: rgba(141, 146, 175, 1);
font-size: 12px;
letter-spacing: 0.14399999380111694px;
white-space: nowrap;
text-align: center;
margin: 0 0 0 14px;
}
</style>
\ No newline at end of file
<template>
<div class="mx-5">
<div class="wrap22 flex items-center">
<div class="box1 flex-col flex-grow">
<span class="info8">建信银行为您量身定做打造良好的信贷体验</span>
<div class="layer4 flex-row">
<span class="info9">建信个人贷</span>
<span class="word24">2021-07-10</span>
</div>
</div>
<div class="box2 flex-col ml-4 flex-shrink-0">
<img
class="pic3"
referrerpolicy="no-referrer"
src="https://lanhu.oss-cn-beijing.aliyuncs.com/SketchPnge2c0a67c1d16ceff7bcf9fba3660fffcbd22643881df43f966f78f68c95b4907"
/>
</div>
</div>
<div class="wrap23 flex-col"></div>
</div>
</template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
export default defineComponent({});
</script>
<style scoped>
.wrap22 {
height: 88px;
justify-content: space-between;
margin: 21px 0 0;
}
.box1 {
z-index: auto;
height: 88px;
}
.info8 {
z-index: 205;
height: 50px;
display: block;
overflow-wrap: break-word;
color: rgba(27, 31, 55, 1);
font-size: 14px;
letter-spacing: 0.1679999977350235px;
font-family: PingFangSC-Medium;
line-height: 25px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
}
.layer4 {
z-index: auto;
height: 25px;
margin-top: 13px;
justify-content: space-between;
}
.info9 {
z-index: 206;
height: 25px;
display: block;
overflow-wrap: break-word;
color: rgba(141, 146, 175, 1);
font-size: 12px;
letter-spacing: 0.14399999380111694px;
line-height: 25px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
}
.word24 {
z-index: 207;
height: 25px;
display: block;
overflow-wrap: break-word;
color: rgba(141, 146, 175, 1);
font-size: 12px;
letter-spacing: 0.14399999380111694px;
line-height: 25px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
}
.box2 {
z-index: 209;
position: relative;
height: 80px;
border-radius: 20px;
overflow: hidden;
background: url(https://lanhu.oss-cn-beijing.aliyuncs.com/SketchPngd7b6ced5c00064ccb38620d2a9de003cbd2e2688ac377f17fc74f6fba4dadd11) -1px
0px no-repeat;
margin-top: 3px;
}
.pic3 {
width: 80px;
height: 80px;
}
.wrap23 {
height: 1px;
border: 1px solid #e7e7e7;
margin-top: 10px;
}
</style>
\ No newline at end of file
<template>
<div class="wrap18 flex mx-5 overflow-hidden">
<div class="flex-shrink-0 block2 outer3" style="width: 44%">
<div class="flex-col">
<div class="flex-col">
<div class="group2 mt-2 ml-2 flex items-center justify-center">
<img
class="icon9 mr-1"
referrerpolicy="no-referrer"
src="https://lanhu.oss-cn-beijing.aliyuncs.com/SketchPngb67f1b6bfda58737e89dadee59bd68fad0b4964489b7942f9159db2c704f25e4"
/>
<span class="word26">正在直播</span>
</div>
</div>
</div>
</div>
<div class="flex flex-col justify-center items-center mx-2.5">
<p class="word18 overflow-ellipsis overflow-hidden">
知名财经专家现场精彩讲座
</p>
<p class="word19 overflow-ellipsis overflow-hidden">
建设银行财经专家分析
</p>
</div>
</div>
</template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
import Icon from "../common/Icon.vue";
export default defineComponent({ components: { Icon } });
</script>
<style scoped>
.wrap18 {
height: 110px;
border-radius: 20px;
background-color: rgba(255, 255, 255, 1);
box-shadow: 0px 2px 13px 0px rgba(240, 246, 252, 1);
}
.word18 {
z-index: 82;
display: block;
overflow-wrap: break-word;
color: rgba(27, 31, 55, 1);
font-size: 16px;
letter-spacing: 0.19200000166893005px;
font-family: PingFangSC-Medium;
line-height: 22px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
}
.word19 {
z-index: 94;
display: block;
overflow-wrap: break-word;
color: rgba(27, 31, 55, 1);
font-size: 12px;
letter-spacing: 0.14399999380111694px;
white-space: nowrap;
line-height: 17px;
text-align: center;
align-self: flex-start;
margin-top: 10px;
}
.outer3 {
overflow: hidden;
background: url(https://lanhu.oss-cn-beijing.aliyuncs.com/SketchPng7071930f7e4936335b32a1512a498654730fabf8a2a83c8137f07d12a7c2b4bd)
100% no-repeat;
background-size: cover;
}
.block2 {
background: url(https://lanhu.oss-cn-beijing.aliyuncs.com/SketchPngb5e34933d0e615000378ebf1491cce32e934e21b7f3de7cddbddd3f05e03ed7a)
100% no-repeat;
background-size: cover;
}
.group2 {
width: fit-content;
padding: 0 9px;
z-index: 86;
height: 20px;
border-radius: 10px;
background-color: rgba(237, 110, 80, 1);
}
.icon9 {
z-index: 88;
width: 11px;
height: 12px;
}
.word26 {
z-index: 87;
display: block;
overflow-wrap: break-word;
color: rgba(255, 255, 255, 1);
font-size: 12px;
letter-spacing: 0.14399999380111694px;
white-space: nowrap;
line-height: 17px;
text-align: left;
}
</style>
\ No newline at end of file
<template>
<div class="wrap15 flex mx-5 items-center">
<div class="bd5 ml-4">
<p class="word14">1000<span class="unit"></span></p>
<p class="txt8">最高可借</p>
</div>
<div
class="bd6 flex flex-col flex-shrink overflow-hidden overflow-ellipsis"
>
<span class="word15">抵押贷</span>
<span class="txt10">在家有房即可办理</span>
<span class="word16">在线审批15分钟出结果</span>
</div>
<div class="flex-grow"></div>
<icon name="icon-gengduo" color="#979BB6" size="15" class="mr-6" />
</div>
</template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
import Icon from "../common/Icon.vue";
export default defineComponent({ components: { Icon } });
</script>
<style scoped>
.wrap15 {
z-index: 98;
height: 109px;
border-radius: 20px;
background-color: rgba(255, 255, 255, 1);
box-shadow: 0px 2px 13px 0px rgba(240, 246, 252, 1);
}
.wrap16 {
z-index: auto;
}
.bd5 {
z-index: auto;
}
.unit {
font-size: 12px;
font-family: PingFangHK-Regular, PingFangHK;
font-weight: 400;
color: #f03a30;
line-height: 17px;
}
.word14 {
z-index: 106;
display: block;
overflow-wrap: break-word;
color: rgba(240, 58, 48, 1);
font-size: 30px;
letter-spacing: 0.36000001430511475px;
font-family: DINAlternate-Bold;
white-space: nowrap;
line-height: 35px;
}
.txt8 {
z-index: 108;
display: block;
overflow-wrap: break-word;
color: rgba(141, 146, 175, 1);
font-size: 12px;
letter-spacing: 0.14399999380111694px;
white-space: nowrap;
line-height: 17px;
align-self: flex-start;
margin: 5px 0 0 0px;
}
.txt9 {
z-index: 107;
display: block;
overflow-wrap: break-word;
color: rgba(240, 58, 48, 1);
font-size: 12px;
letter-spacing: 0.14399999380111694px;
font-family: PingFangHK-Regular;
white-space: nowrap;
line-height: 17px;
text-align: center;
margin: 20px 0 0 5px;
}
.bd6 {
z-index: auto;
height: 69px;
margin-left: 19px;
}
.word15 {
z-index: 103;
display: block;
overflow-wrap: break-word;
color: rgba(27, 31, 55, 1);
font-size: 16px;
letter-spacing: 0.19200000166893005px;
font-family: PingFangSC-Semibold;
white-space: nowrap;
line-height: 22px;
text-align: left;
align-self: flex-start;
}
.txt10 {
z-index: 104;
display: block;
overflow-wrap: break-word;
color: rgba(27, 31, 55, 1);
font-size: 12px;
letter-spacing: 0.14399999380111694px;
white-space: nowrap;
line-height: 17px;
text-align: left;
align-self: flex-start;
margin-top: 10px;
}
.word16 {
z-index: 105;
display: block;
overflow-wrap: break-word;
color: rgba(141, 146, 175, 1);
font-size: 12px;
letter-spacing: 0.14399999380111694px;
white-space: nowrap;
line-height: 17px;
text-align: left;
margin-top: 3px;
}
.label9 {
z-index: 99;
height: 14px;
margin: 27px 0 0 69px;
}
</style>
\ No newline at end of file
<template>
<div class="navbar w-full">
<div
class="
h-full
theBar
flex
items-center
px-5
justify-center
relative
bg-app-bg
"
>
<div class="relative w-full flex items-center justify-center">
<icon
@click="$router.go(-1)"
name="icon-fanhui"
class="absolute left-0"
size="18"
color="#343640"
/>
<div>{{ title }}</div>
</div>
</div>
<div class="some-block"></div>
</div>
</template>
<script lang="ts">
import Vue, { defineComponent } from "vue";
import Icon from "../common/Icon.vue";
export default defineComponent({
components: { Icon },
props: ["title"],
});
</script>
<style lang="less" scoped>
.navbar {
.theBar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
height: 46px;
}
.some-block {
height: 46px;
}
}
</style>
\ No newline at end of file
<template>
<Popup
v-model:show="visible"
position="right"
style="height: 100vh; width: 86%"
class="relative"
>
<div class="flex flex-col h-full">
<div class="mx-5 flex items-center justify-center relative mt-2.5">
<icon
color="#000000"
name="icon-a-shanchu1"
class="absolute left-0"
@click="clickClose"
/>
<div class="title">{{ title || "此处是标题" }}</div>
</div>
<div class="flex-grow overflow-hidden">
<div class="h-full overflow-auto px-5">
<slot />
</div>
</div>
<div class="flex">
<div
class="flex-grow btn flex justify-center items-center"
@click="leftBtnActive && $emit('clickLeft')"
:class="{
'btn-active': leftBtnActive,
}"
>
{{ leftBtnName }}
</div>
<div class="w-0.5"></div>
<div
@click="rightBtnActive && $emit('clickRight')"
class="flex-grow btn flex justify-center items-center"
:class="{
'btn-active': rightBtnActive,
}"
>
{{ rightBtnName }}
</div>
</div>
</div>
</Popup>
</template>
<script lang="ts">
import Vue, { defineComponent } from "vue";
import { Popup } from "vant";
import Icon from "@/components/common/Icon.vue";
export default defineComponent({
components: {
Popup,
Icon,
},
props: {
leftBtnName: { type: String, default: "重置" },
rightBtnName: { type: String, default: "完成" },
leftBtnActive: {
type: Boolean,
default: true,
},
rightBtnActive: {
type: Boolean,
default: true,
},
title: String,
show: Boolean,
setShow: {
type: Function,
required: true,
},
},
methods: {
clickClose(): void {
this.setShow(false);
},
},
computed: {
visible: {
get(): boolean {
return this.show;
},
set(v: boolean): void {
this.setShow(false);
},
},
},
});
</script>
<style lang="less" scoped>
.btn {
height: 45px;
background: #e7e7e7;
font-size: 14px;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #ffffff;
}
.btn-active {
font-weight: 600;
color: #ffffff;
background: #3e4faf;
}
.title {
font-size: 16px;
font-family: PingFangSC-Semibold, PingFang SC;
font-weight: 600;
color: #1b1f37;
}
</style>
\ No newline at end of file
<template>
<div>
<div class="group-title mt-8">银行名称</div>
<SelectList
class="mt-5"
:list="bankList"
:selecteds="selectedBanks"
:setSelecteds="setBanks"
/>
<div class="group-title mt-8">利率 (%)</div>
<div class="section10 flex-row">
<div class="mod5 flex-col">
<div class="layer4 flex-row">
<div class="word24">
<input
v-model.number="min_"
type="number"
placeholder="最低利率"
class="bg-transparent w-full"
/>
</div>
<div class="word25">%</div>
</div>
</div>
<div class="mod6 flex-col"></div>
<div class="mod7 flex-col">
<div class="main12 flex-row">
<div class="txt12">
<input
type="number"
v-model.number="max_"
placeholder="最高利率"
class="bg-transparent w-full"
/>
</div>
<div class="word26">%</div>
</div>
</div>
</div>
<div class="group-title mt-8">期限</div>
<SelectList
class="mt-5"
:list="peridList"
:selecteds="selectedPerids"
:setSelecteds="setSelectedPerids"
/>
</div>
</template>
<script lang="ts">
import Vue, { defineComponent } from "vue";
import SelectList from "@/components/SelectList/index.vue";
export default defineComponent({
components: {
SelectList,
},
props: {
bankList: Array,
selectedBanks: Array,
setBanks: Function,
peridList: Array,
selectedPerids: Array,
setSelectedPerids: Function,
min: [Number, String],
max: [Number, String],
setMin: {
type: Function,
required: true,
},
setMax: {
type: Function,
required: true,
},
},
computed: {
min_: {
get(): number | string | undefined {
return this.min;
},
set(v: number | string): void {
this.setMin(v);
},
},
max_: {
get(): number | string | undefined {
return this.max;
},
set(v: number | string): void {
this.setMax(v);
},
},
},
});
</script>
<style lang="less" scoped>
.group-title {
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #1b1f37;
}
.section10 {
z-index: auto;
width: 282px;
height: 40px;
justify-content: space-between;
margin-top: 20px;
}
.mod5 {
z-index: 136;
height: 40px;
border-radius: 5px;
background-color: rgba(247, 247, 250, 1);
width: 116px;
justify-content: center;
align-items: flex-end;
padding-right: 10px;
}
.layer4 {
z-index: auto;
width: 82px;
height: 20px;
justify-content: space-between;
}
.word24 {
z-index: 140;
width: 56px;
display: block;
overflow-wrap: break-word;
font-size: 14px;
font-family: PingFangSC-Regular;
white-space: nowrap;
color: #1b1f37;
line-height: 20px;
text-align: left;
}
.word25 {
z-index: 138;
width: 14px;
display: block;
overflow-wrap: break-word;
font-size: 14px;
color: #1b1f37;
font-family: PingFangSC-Regular;
white-space: nowrap;
line-height: 20px;
text-align: left;
}
.mod6 {
z-index: 145;
width: 14px;
height: 1px;
background: url(https://lanhu.oss-cn-beijing.aliyuncs.com/SketchPnga0e9464c2bc2666ea94aaa969a4fbb2853a62a3a30b32f0a92310f37426eb2d6)
0px 0px no-repeat;
margin-top: 20px;
}
.mod7 {
z-index: 139;
height: 40px;
border-radius: 5px;
background-color: rgba(247, 247, 250, 1);
width: 116px;
justify-content: center;
align-items: flex-end;
padding-right: 10px;
}
.main12 {
z-index: auto;
width: 76px;
height: 20px;
justify-content: space-between;
}
.txt12 {
z-index: 143;
width: 56px;
display: block;
overflow-wrap: break-word;
color: #1b1f37;
font-size: 14px;
font-family: PingFangSC-Regular;
white-space: nowrap;
line-height: 20px;
text-align: left;
}
.word26 {
z-index: 141;
width: 14px;
display: block;
overflow-wrap: break-word;
color: #1b1f37;
font-size: 14px;
font-family: PingFangSC-Regular;
white-space: nowrap;
line-height: 20px;
text-align: left;
}
</style>
\ No newline at end of file
<template>
<div
class="
item
overflow-hidden overflow-ellipsis
flex
items-center
justify-center
"
:class="{
active: active,
}"
>
{{ name }}
</div>
</template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
export default defineComponent({
props: ["name", "active"],
});
</script>
<style lang="less" scoped>
.item {
width: 131px;
height: 40px;
background: #f7f7fa;
border-radius: 5px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #1b1f37;
}
.active {
background: #3e4faf;
color: #ffffff;
}
</style>
\ No newline at end of file
<template>
<div class="flex flex-wrap justify-between">
<select-item
class="mb-2.5"
v-for="item in list"
:key="item.id"
:name="item.name"
@click="clickItem(item.id)"
:active="selecteds.includes(item.id)"
/>
</div>
</template>
<script lang="ts">
import Vue, { defineComponent } from "vue";
import SelectItem from "./SelectItem.vue";
export default defineComponent({
props: ["list", "selecteds", "setSelecteds"],
components: { SelectItem },
methods: {
clickItem(id: any) {
if (this.selecteds.includes(id)) {
this.setSelecteds(this.selecteds.filter((i: any) => i !== id));
} else {
this.setSelecteds([...this.selecteds, id]);
}
},
},
});
</script>
\ No newline at end of file
<template>
<div
class="
text-xs
px-3
py-2
text-center
cursor-pointer
rounded
my-3
flex
items-center
justify-center
"
:class="[disabled ? 'filter grayscale' : '', loading ? ' opacity-75' : '']"
@click="eventEmit"
>
{{ text }} <slot name="icon-right"></slot>
<Loading type="spiner" size="16" class="ml-2" v-if="loading" />
</div>
</template>
<script lang="ts">
import { Loading } from "vant";
import Vue, {defineComponent} from "vue";
export default defineComponent({
components: {
Loading,
},
name: "AppIcon",
props: {
size: String,
disabled: {
type: Boolean,
default: false,
},
text: {
type: String,
required: true,
},
border: {
type: String,
default: "border border-app-dark-4",
},
loading: {
type: Boolean,
default: false,
},
},
methods: {
eventEmit(v: any) {
if (this.disabled || this.loading) {
return;
}
this.$emit("btnClicked", v);
},
},
});
</script>
<template>
<div class="flex items-center" @click="$emit('change', !checked)">
<img class="w-4 mr-1" :src="checked ? checkedIcon : notCheckedIcon" />
<span>
<slot />
</span>
</div>
</template>
<script>
import Vue, {defineComponent} from "vue";
import notCheckedIcon from '@/assets/icons/not_checked_2.png'
import checkedIcon from '@/assets/icons/checked.png'
// const notCheckedIcon = require("@/assets/icons/not_checked_2.png");
// const checkedIcon = require("@/assets/icons/checked.png");
export default defineComponent({
props: ["checked"],
data() {
return {
notCheckedIcon,
checkedIcon,
};
},
});
</script>
<style>
</style>
\ No newline at end of file
<template>
<div class="object-cover" @click="clickSelf">
<div v-show="type === 'png'">
<img src="@/assets/icons/shiba.png" class="object-cover object-center" />
</div>
<svg
v-show="type === 'svg'"
aria-hidden="true"
:height="size"
:width="size"
:fill="color"
>
<use :xlink:href="'#' + name"></use>
</svg>
</div>
</template>
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
emits: ["click"],
props: {
type: {
type: String,
default: "svg",
},
size: {
type: String,
default: "14px",
},
color: {
type: String,
default: "#ffffff",
},
name: {
type: String,
default: "icon-anquanzhongxin89",
},
},
methods: {
clickSelf() {
this.$emit("click");
},
},
});
</script>
<template>
<Field
class="base-input text-font-white"
:label="label"
:placeholder="placeholder"
:value="value"
@input="handleChange"
:type="getInputType"
:maxlength="maxlength"
autocomplete="off"
>
<template #button>
<div class="flex items-center">
<img
src="@/assets/icons/close.png"
@click="handleClear"
v-if="clearable && value && value.length !== 0"
name="cross"
/>
<slot name="button"></slot>
<img
v-if="type === 'password' && showEye"
:src="showPwd ? eyeOpenIcon : eyeCloseIcon"
@click="handleClickEye"
name="cross"
class="ml-1 eyeIcon"
/>
</div>
</template>
</Field>
</template>
<script lang="ts">
import Vue, { PropType } from "vue";
import { Field } from "vant";
import { tType } from "./types";
import eyeOpenIcon from "@/assets/icons/eye_open.png";
import eyeCloseIcon from "@/assets/icons/eye_close.png";
// const eyeOpenIcon = require("@/assets/icons/eye_open.png");
// const eyeCloseIcon = require("@/assets/icons/eye_close.png");
export default defineComponent({
components: {
Field,
// Icon,
},
props: {
type: {
type: String as PropType<tType>,
default: "text",
},
placeholder: String,
clearable: {
type: Boolean,
default: false,
},
value: String,
maxlength: Number,
label: {
type: String,
default: "",
},
showEye: {
type: Boolean,
default: true,
},
},
data() {
return {
showPwd: false,
eyeOpenIcon,
eyeCloseIcon,
};
},
computed: {
getInputType(): string {
if (this.type === "password") {
return this.showPwd ? "text" : "password";
} else {
return this.type;
}
},
},
methods: {
handleClickEye() {
this.showPwd = !this.showPwd;
},
handleChange(value: string) {
this.$emit("change", value);
},
handleClear() {
this.$emit("change", "");
},
},
});
</script>
<style scoped lang="less">
@color1: #68739c;
@caretColor: #8899b3;
@textColor: #eef1f6;
.base-input {
background-color: transparent;
// border-bottom: 1px solid @color1;
caret-color: @caretColor;
padding: 10px 0px;
/deep/ input {
color: @textColor;
}
.eyeIcon {
width: 14px;
}
}
.base-input::after {
left: 0;
right: 0;
border-bottom: 1px solid @color1;
}
</style>
\ No newline at end of file
export type tType = "password" | "number" | "text"
\ No newline at end of file
<template>
<div class="drag" ref="dragDiv">
<div class="drag_bg"></div>
<div class="drag_text">{{ confirmWords }}</div>
<div
ref="moveDiv"
@touchstart="mousedownFn($event)"
:class="{ handler_ok_bg: confirmSuccess }"
class="handler handler_bg"
style="position: absolute; top: 0px; left: 0px; bottom: 0px"
></div>
</div>
</template>
<script>
export default {
data() {
return {
beginClientX: 0 /*距离屏幕左端距离*/,
mouseMoveStata: false /*触发拖动状态 判断*/,
maxwidth: "" /*拖动最大宽度,依据滑块宽度算出来的*/,
confirmWords: "拖动滑块验证" /*滑块文字*/,
confirmSuccess: false /*验证成功判断*/,
};
},
methods: {
mousedownFn: function (e) {
if (!this.confirmSuccess) {
e.preventDefault && e.preventDefault(); //阻止文字选中等 浏览器默认事件
this.mouseMoveStata = true;
this.beginClientX = e.changedTouches[0].clientX;
}
}, //mousedoen 事件
successFunction() {
this.confirmSuccess = true;
this.$emit("confirm", true);
this.confirmWords = "验证通过";
if (window.addEventListener) {
document
.getElementsByTagName("html")[0]
.removeEventListener("touchmove", this.mouseMoveFn);
document
.getElementsByTagName("html")[0]
.removeEventListener("touchend", this.moseUpFn);
} else {
document
.getElementsByTagName("html")[0]
.removeEventListener("touchend", () => {});
}
document.getElementsByClassName("drag_text")[0].style.color = "#fff";
document.getElementsByClassName("handler")[0].style.left =
this.maxwidth + "px";
document.getElementsByClassName("drag_bg")[0].style.width =
this.maxwidth + "px";
}, //验证成功函数
mouseMoveFn(e) {
if (this.mouseMoveStata) {
let width = e.changedTouches[0].clientX - this.beginClientX;
if (width > 0 && width <= this.maxwidth) {
document.getElementsByClassName("handler")[0].style.left =
width + "px";
document.getElementsByClassName("drag_bg")[0].style.width =
width + "px";
} else if (width > this.maxwidth) {
this.successFunction();
}
}
}, //mousemove事件
moseUpFn(e) {
this.mouseMoveStata = false;
var width = e.changedTouches[0].clientX - this.beginClientX;
if (width < this.maxwidth) {
document.getElementsByClassName("handler")[0].style.left = 0 + "px";
document.getElementsByClassName("drag_bg")[0].style.width = 0 + "px";
}
}, //mouseup事件
},
mounted() {
this.maxwidth =
this.$refs.dragDiv.clientWidth - this.$refs.moveDiv.clientWidth;
document
.getElementsByTagName("html")[0]
.addEventListener("touchmove", this.mouseMoveFn);
document
.getElementsByTagName("html")[0]
.addEventListener("touchend", this.moseUpFn);
},
beforeDestroy() {
document
.getElementsByTagName("html")[0]
.removeEventListener("touchmove", this.mouseMoveFn);
document
.getElementsByTagName("html")[0]
.removeEventListener("touchend", this.moseUpFn);
},
};
</script>
<style scoped>
.drag {
position: relative;
background-color: #e8e8e8;
width: 100%;
height: 34px;
line-height: 34px;
text-align: center;
}
.handler {
width: 40px;
border: 1px solid #ccc;
cursor: move;
}
.handler_bg {
background: #fff
url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTEyNTVEMURGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTEyNTVEMUNGMkVFMTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo2MTc5NzNmZS02OTQxLTQyOTYtYTIwNi02NDI2YTNkOWU5YmUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+YiRG4AAAALFJREFUeNpi/P//PwMlgImBQkA9A+bOnfsIiBOxKcInh+yCaCDuByoswaIOpxwjciACFegBqZ1AvBSIS5OTk/8TkmNEjwWgQiUgtQuIjwAxUF3yX3xyGIEIFLwHpKyAWB+I1xGSwxULIGf9A7mQkBwTlhBXAFLHgPgqEAcTkmNCU6AL9d8WII4HOvk3ITkWJAXWUMlOoGQHmsE45ViQ2KuBuASoYC4Wf+OUYxz6mQkgwAAN9mIrUReCXgAAAABJRU5ErkJggg==")
no-repeat center;
}
.handler_ok_bg {
background: #fff
url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA3hpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDo0ZDhlNWY5My05NmI0LTRlNWQtOGFjYi03ZTY4OGYyMTU2ZTYiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NDlBRDI3NjVGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NDlBRDI3NjRGMkQ2MTFFNEI5NDBCMjQ2M0ExMDQ1OUYiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDphNWEzMWNhMC1hYmViLTQxNWEtYTEwZS04Y2U5NzRlN2Q4YTEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NGQ4ZTVmOTMtOTZiNC00ZTVkLThhY2ItN2U2ODhmMjE1NmU2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+k+sHwwAAASZJREFUeNpi/P//PwMyKD8uZw+kUoDYEYgloMIvgHg/EM/ptHx0EFk9I8wAoEZ+IDUPiIMY8IN1QJwENOgj3ACo5gNAbMBAHLgAxA4gQ5igAnNJ0MwAVTsX7IKyY7L2UNuJAf+AmAmJ78AEDTBiwGYg5gbifCSxFCZoaBMCy4A4GOjnH0D6DpK4IxNSVIHAfSDOAeLraJrjgJp/AwPbHMhejiQnwYRmUzNQ4VQgDQqXK0ia/0I17wJiPmQNTNBEAgMlQIWiQA2vgWw7QppBekGxsAjIiEUSBNnsBDWEAY9mEFgMMgBk00E0iZtA7AHEctDQ58MRuA6wlLgGFMoMpIG1QFeGwAIxGZo8GUhIysmwQGSAZgwHaEZhICIzOaBkJkqyM0CAAQDGx279Jf50AAAAAABJRU5ErkJggg==")
no-repeat center;
}
.drag_bg {
background-color: #7ac23c;
height: 34px;
width: 0px;
}
.drag_text {
position: absolute;
top: 0px;
width: 100%;
text-align: center;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
-o-user-select: none;
-ms-user-select: none;
}
</style>
\ No newline at end of file
declare module '*.png';
declare module '*.jpg';
\ No newline at end of file
import { createApp } from 'vue' import { createApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
import 'tailwindcss/tailwind.css'
import store from './store' import store from './store'
import { NoticeBar, Swipe, SwipeItem } from 'vant'
createApp(App).use(store).use(router).mount('#app') createApp(App)
.use(store)
.use(router)
.use(NoticeBar)
.use(Swipe)
.use(SwipeItem)
.mount('#app')
...@@ -4,22 +4,74 @@ import Home from '../views/Home.vue' ...@@ -4,22 +4,74 @@ import Home from '../views/Home.vue'
const routes: Array<RouteRecordRaw> = [ const routes: Array<RouteRecordRaw> = [
{ {
path: '/', path: '/',
redirect: { name: 'Home' },
component: () =>
import(/* webpackChunkName: "withMenu" */ '@/views/withMenu/index.vue'),
children: [
{
path: '/home',
name: 'Home', name: 'Home',
component: Home component: () =>
import(
/* webpackChunkName: "Home" */ '@/views/withMenu/Home/index.vue'
),
},
{
path: '/mine',
name: 'Mine',
component: () =>
import(
/* webpackChunkName: "mine" */ '@/views/withMenu/Mine/index.vue'
),
}, },
{ {
path: '/about', path: '/financialManagement',
name: 'About', name: 'FinancialManagement',
// route level code-splitting component: () =>
// this generates a separate chunk (about.[hash].js) for this route import(
// which is lazy-loaded when the route is visited. /* webpackChunkName: "fns" */ '@/views/withMenu/FinancialManagement/index.vue'
component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') ),
} },
{
path: '/loan',
name: 'Loan',
component: () =>
import(
/* webpackChunkName: "mine" */ '@/views/withMenu/Loan/index.vue'
),
},
],
},
{
path: '/fnsList',
name: 'FnsList',
component: () => import('@/views/FnsList/index.vue'),
},
// {
// path: '/auth',
// component: () => import('@/views/Auth/index.vue'),
// redirect: {
// name: 'Login',
// },
// children: [
// {
// path: '/auth/Login',
// name: 'Login',
// component: () => import('@/views/Auth/Login/index.vue'),
// },
// ],
// },
{
path: '/:pathMatch(.*)*',
redirect: {
name: 'Home',
},
},
] ]
const router = createRouter({ const router = createRouter({
history: createWebHistory(process.env.BASE_URL), history: createWebHistory(process.env.BASE_URL),
routes routes,
}) })
export default router export default router
export interface iUserMsg {
token: string
userInfo: any
}
import { iUserMsg } from '@/types/userMsg'
const USER_MSG = 'USER_MSG'
export function setUserMsg(msg: iUserMsg) {
localStorage.setItem(USER_MSG, JSON.stringify(msg))
}
export function getUserMsg(): iUserMsg | undefined {
const value = localStorage.getItem(USER_MSG)
return (value && JSON.parse(value)) || undefined
}
export function deleteUserMsg() {
localStorage.removeItem(USER_MSG)
}
<template>
<div class="about">
<h1>This is an about page</h1>
</div>
</template>
This diff is collapsed.
import { iRememberPhonePwd } from "./types";
const KEY_REMEMBER_PWD = 'KEY_REMEMBER_PWD'
export default class LoginService {
static instance: LoginService
static getIntance() {
if (!LoginService.instance) LoginService.instance = new LoginService();
return LoginService.instance;
}
addPhoneWithPwdToStorage(phone: string, pwd: string) {
const list = this.getRememberedPhonePwdList();
const index = list.findIndex(i => i.phone === phone)
if (index === -1) {
list.push({
phone,
pwd
})
} else {
list.splice(index, 1, { phone, pwd })
}
localStorage.setItem(KEY_REMEMBER_PWD, JSON.stringify(list))
}
getRememberedPhonePwdList(): iRememberPhonePwd[] {
const value = localStorage.getItem(KEY_REMEMBER_PWD)
const list = value && JSON.parse(value) || []
return list;
}
deletePhoneInStorage(phone: string) {
const list = this.getRememberedPhonePwdList()
const newList = list.filter(i => i.phone !== phone)
localStorage.setItem(KEY_REMEMBER_PWD, JSON.stringify(newList))
}
}
\ No newline at end of file
<template>
<div class="flex flex-col w-11/12 mx-auto py-5 text-font-white">
<div class="flex justify-between items-center">
<div class="w-3/12">
<app-icon name="icon-fanhui" @click="handleClickClose"></app-icon>
</div>
<div class="text-center w-6/12">乐映用户协议</div>
<div class="w-3/12"></div>
</div>
<div class="flex py-6 justify-center">
<img src="@/assets/img/cmp_logo.png" class="h-12" alt="" />
</div>
<div></div>
</div>
</template>
<script lang="ts">
import Vue, { defineComponent } from "vue";
import closeIcon from "@/assets/icons/close_large.png";
export default defineComponent({
props: ["setOverlayShow"],
data() {
return {
closeIcon,
};
},
components: {
"app-icon": () => import("@/components/common/Icon.vue"),
},
methods: {
handleClick() {
console.log(123);
},
handleClickClose() {
this.setOverlayShow(false);
},
},
});
</script>
<style>
.userAgreement {
background: #131934;
}
</style>
\ No newline at end of file
<template>
<div class="">
<Input
:placeholder="placeholder"
:clearable="clearable"
:maxlength="maxlength"
:value="value"
:type="type"
@change="handleChange"
>
<template #button>
<div>
<div
v-if="smsCount === 60"
@click="handleClickSendSms"
class="text-font-blue"
:class="{ 'text-font-gray': !phoneValid || smsLock }"
>
获取验证码
</div>
<div v-else class="text-font-blue">已发送 {{ smsCount }} S</div>
</div>
</template>
</Input>
<div
class="mt-2 float-right text-sm text-font-blue"
v-if="voiceActive && sendVoiceFunc"
>
<div
v-if="voiceCount === 60 && !voiceHasSended60Ago"
class="flex items-center"
:class="{ 'text-font-gray': voiceLock }"
>
收不到验证码?试试
<span
class="text-font-blue"
@click="handleClickSendVoice"
:class="{ 'text-font-gray': voiceLock }"
>语音验证</span
>
</div>
<div
@click="handleClickSendVoice"
v-else-if="voiceCount === 60 && voiceHasSended60Ago"
:class="{ 'text-font-gray': voiceLock }"
>
获取语音验证
</div>
<div v-else>请注意接听语音验证电话 ({{ voiceCount }}) S</div>
</div>
<div class="clear-right"></div>
</div>
</template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
import Input from "@/components/common/Input/index.vue";
export default defineComponent({
components: {
Input,
},
props: {
placeholder: String,
clearable: Boolean,
value: String,
type: String,
handleChange: Function,
maxlength: Number,
phone: String,
sendSmsFunc: Function,
sendVoiceFunc: {
type: Function,
required: false,
},
phoneValid: Boolean,
sendSmsAuto: {
type: Boolean,
default: false,
},
},
data() {
return {
smsCount: 60,
voiceCount: 60,
voiceActive: false,
voiceHasSended60Ago: false,
smsLock: false,
voiceLock: false,
timerId1: 0,
timerId2: 0,
};
},
mounted() {
if (this.phoneValid && this.sendSmsAuto) {
this.handleClickSendSms();
}
},
methods: {
async handleClickSendSms() {
if (!this.phoneValid) return;
if (this.smsLock === true) return;
this.smsLock = true;
try {
await this.sendSmsFunc(this.phone);
} catch (err) {
this.smsLock = false;
return;
}
this.smsCount--;
this.timerId1 = window.setInterval(() => {
this.smsCount--;
if (this.smsCount === -1) {
this.smsCount = 60;
this.voiceActive = true;
this.smsLock = false;
window.clearInterval(this.timerId1);
}
}, 1000);
},
async handleClickSendVoice() {
if (!this.phoneValid) return;
if (this.voiceLock === true) return;
this.voiceLock = true;
await this.sendVoiceFunc(this.phone);
this.voiceCount--;
this.timerId2 = window.setInterval(() => {
this.voiceCount--;
if (this.voiceCount === -1) {
this.voiceCount = 60;
this.voiceLock = false;
this.voiceHasSended60Ago = true;
window.clearInterval(this.timerId2);
}
}, 1000);
},
},
beforeDestroy() {
clearInterval(this.timerId1);
clearInterval(this.timerId2);
},
});
</script>
<style>
</style>
\ No newline at end of file
<template>
<transition name="fade" mode="out-in" :duration="100">
<Button
:key="disabled + text"
:text="text"
class="rounded-full h-8"
@btnClicked="handleCliCkBtn"
border="border-0"
:class="[
disabled ? 'text-font-white bg-font-blue filter grayscale' : 'bg-font-blue',
disabled ? 'text-font-white bg-font-blue filter grayscale' : ' text-white ',
loading ? 'opacity-75': '',
]"
>
<template #icon-right>
<div>
<div v-if="!loading">
<img
v-if="!disabled"
class="ml-2"
src="@/assets/icons/arrow-right.png"
alt="arrow-right"
/>
<img
v-else
class="ml-2"
src="@/assets/icons/arrow-right-dark.png"
alt="arrow-right"
/>
</div>
<div v-else>
<Loading class="w-4 ml-2" />
</div>
</div>
</template>
</Button>
</transition>
</template>
<script lang="ts">
import Button from "@/components/common/Btn.vue";
import { Loading } from "vant";
import Vue, {defineComponent} from "vue";
export default defineComponent({
components: {
Button,
Loading,
},
props: {
text: String,
disabled: Boolean,
loading: {
type: Boolean,
default: false,
},
},
methods: {
handleCliCkBtn(e: MouseEvent) {
if (this.disabled) return;
if (this.loading) return;
this.$emit("click", e);
},
},
});
</script>
<style>
.darkBtn {
background: #1d2649;
color: #8899b3;
}
</style>
<template>
<div class="w-full phoneInput" ref="phoneInput">
<Input
:placeholder="placeholder"
:maxlength="maxlength"
:clearable="true"
:value="value"
:type="type"
@change="handleChange"
>
<template #button>
<img
:src="arrowDownIcon"
alt=""
ref="arrowImg"
class="ml-2 transform transition-all"
:class="{ 'rotate-180': !arrowDown }"
@click="handleClickArrowIcon"
/>
</template>
</Input>
<div class="w-full relative mt-px">
<div
class="
absolute
left-0
right-0
overflow-auto
h-0
transition-all
z-10
text-font-white
bg-font-light-black
"
:class="{ 'h-24': !arrowDown }"
>
<div
v-for="(item, index) in phonePwdList"
:key="index"
class="
h-8
flex
items-center
justify-between
bg-font-light-black
hover:bg-font-black
"
@click="handleClickPhoneItem(item)"
>
<div class="ml-4">{{ item.phone }}</div>
<img
src="@/assets/icons/close.png"
@click="handleClickDelete(item.phone)"
class="mr-4 closeIcon"
/>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
import Input from "@/components/common/Input/index.vue";
import LoginService from "../../LoginService";
import { iRememberPhonePwd } from "../../types";
import eyeOpenIcon from "@/assets/icons/eye_open.png";
import eyeCloseIcon from "@/assets/icons/eye_close.png";
import arrowDownIcon from "@/assets/icons/arrow_down.png";
let NotCloseList = [] as Element[];
export default defineComponent({
components: {
Input,
},
props: {
type: {
type: String,
default: "text",
},
placeholder: String,
clearable: {
type: Boolean,
default: false,
},
value: String,
maxlength: Number,
handlePhoneChange: Function,
},
data() {
return {
showPwd: false,
eyeOpenIcon,
eyeCloseIcon,
phonePwdList: [] as iRememberPhonePwd[],
arrowDownIcon,
arrowDown: true,
};
},
methods: {
handleClickPhoneItem(item: iRememberPhonePwd) {
this.$emit("selectItem", item);
},
handleChange(v: string) {
this.$emit("change", v);
},
handleClickArrowIcon() {
this.arrowDown = !this.arrowDown;
if (!this.arrowDown) {
this.fetchList();
this.$nextTick(() => {
this.initNotCloseList();
document.removeEventListener("click", this.callback);
document.addEventListener("click", this.callback);
});
}
},
callback(e: MouseEvent) {
const notClose = NotCloseList.some((el) => {
return el.contains(e.target as Node);
});
if (!notClose) {
this.arrowDown = true;
}
},
initNotCloseList() {
const phoneInputEle = this.$refs.phoneInput as Element;
const arrowImgEle = this.$refs.arrowImg as Element;
const closeIcons = Array.from(
phoneInputEle.querySelectorAll(".closeIcon")
);
NotCloseList = closeIcons;
NotCloseList.push(arrowImgEle);
},
fetchList() {
const list = LoginService.getIntance().getRememberedPhonePwdList();
this.phonePwdList = list;
},
handleClickDelete(phone: string) {
LoginService.getIntance().deletePhoneInStorage(phone);
this.fetchList();
},
},
});
</script>
<style scoped lang="less">
</style>
\ No newline at end of file
export const phoneConfig = {
maxLen: 11,
placeholder: "请输入手机号",
type: 'number',
validate(value: string) {
return value.length === 11;
}
}
export const codeConfig = {
maxLen: 4,
placeholder: "请输入验证码",
type: 'number',
validate(value: string) {
return value.length === 4;
}
}
export const pwdConfig = {
maxLen: 30,
placeholder: "请输入密码(6-30个字符)",
placeholder2: "请设置新密码(6-30个字符)",
placeholder3: "请输入原密码",
type: 'password',
validate(value: string) {
return value.length >= 6 && value.length <= 30;
},
}
<template>
<div class="px-5">
<Login
title="欢迎来到一幕"
:accountStatusCheckFunc="accountStatusCheckFunc"
:sendSmsFunc="sendSmsFunc"
:registerFunc="registerFunc"
:loginByCodeFunc="loginByCodeFunc"
:loginByPwdFunc="loginByPwdFunc"
/>
</div>
</template>
<script lang="ts">
import Vue, { VueConstructor } from "vue";
import Login from "./Login.vue";
export default (
Vue as VueConstructor<
Vue & {
sendSmsFunc: any;
accountStatusCheckFunc: any;
registerFunc: any;
loginByCodeFunc: any;
loginByPwdFunc: any;
}
>
).extend({
components: { Login },
inject: {
sendSmsFunc: "sendSmsFunc",
accountStatusCheckFunc: "accountStatusCheckFunc",
registerFunc: "registerFunc",
loginByCodeFunc: "loginByCodeFunc",
loginByPwdFunc: "loginByPwdFunc",
},
methods: {},
});
</script>
<style>
</style>
\ No newline at end of file
/* eslint-disable */
export enum eAccountType {
NULL,
NO_REG, // 账号没注册
REG_NOPD, // 账号已注册 为设置密码
REG_PDSET, // 账号已注册 已设置密码
}
export enum eLoginWay {
NULL,
PWD, // 密码
CODE // 验证码
}
export interface iRememberPhonePwd {
phone: string;
pwd: string;
}
/* 检测账户状态 */
export type tAccountStatusCheckFunc = (phone: string) => Promise<eAccountType>
/* 发送验证码 */
export type tSendSmsFunc = (phone: string) => Promise<any>
/* 发送语音验证码 */
export type tSendVoiceFunc = (phone: string) => Promise<any>
/* 注册,请求成功后的后续操作需要写在本方法中,如保存token、路由转跳*/
export type tRegisterFunc = (phone: string, code: string) => Promise<boolean>
/* 登录 请求成功后的后续操作需要写在本方法, 如保存token、路由转跳*/
export type tLoginByCodeFunc = (phone: string, code: string) => Promise<any>
export type tLoginByPwdFunc = (phone: string, pwd: string) => Promise<any>
export interface iLoginCmpProps {
accountStatusCheckFunc: tAccountStatusCheckFunc;
registerFunc: tRegisterFunc;
loginByCodeFunc: tLoginByCodeFunc;
loginByPwdFunc: tLoginByPwdFunc;
sendSmsFunc: tSendSmsFunc,
sendVoiceFunc: tSendVoiceFunc,
}
<template>
<div class="">
<div class="text-font-white text-2xl mt-16">找回密码</div>
<PhoneInput
class="mt-8"
:placeholder="phoneConfig.placeholder"
:maxlength="phoneConfig.maxLen"
:clearable="true"
:value="phone"
:type="phoneConfig.type"
@change="handlePhoneChange"
>
</PhoneInput>
<CodeInput
:placeholder="codeConfig.placeholder"
:maxlength="codeConfig.maxLen"
:value="code"
:type="codeConfig.type"
:handleChange="handleCodeChange"
:phone="phone"
:sendSmsFunc="sendSmsFunc"
:sendVoiceFunc="sendVoiceFunc"
:phoneValid="phoneValid"
>
</CodeInput>
<Input
:placeholder="pwdConfig.placeholder2"
:maxlength="pwdConfig.maxLen"
:value="pwd"
:type="pwdConfig.type"
@change="handlePwdChange"
>
<template #button> </template>
</Input>
<LoginButton
class="mt-8"
text="确定"
:disabled="getConfirmDisabled"
@click="handleClickConfirm"
:loading="loading"
></LoginButton>
</div>
</template>
<script lang="ts">
import Vue, { PropType } from "vue";
import PhoneInput from "../Login/components/PhoneInput/index.vue";
import { phoneConfig, codeConfig, pwdConfig } from "../Login/const";
import { tSendSmsFunc, tSendVoiceFunc } from "../Login/types";
import Input from "@/components/common/Input/index.vue";
import LoginButton from "../Login/components/LoginButton/index.vue";
import CodeInput from "../Login/components/CodeInput/index.vue";
import { tSetPwdFunc } from "../PwdSetting/types";
export default defineComponent({
components: {
PhoneInput,
Input,
LoginButton,
CodeInput,
},
props: {
sendSmsFunc: {
type: Function as PropType<tSendSmsFunc>,
required: true,
},
sendVoiceFunc: {
type: Function as PropType<tSendVoiceFunc>,
required: true,
},
setPwdFunc: {
type: Function as PropType<tSetPwdFunc>,
required: true,
},
},
data() {
return {
phoneConfig,
codeConfig,
pwdConfig,
phone: "",
code: "",
pwd: "",
loading: false,
};
},
methods: {
handlePhoneChange(value: string) {
this.phone = value;
},
handleCodeChange(v: string) {
this.code = v;
},
sendSms() {
return this.sendSmsFunc(this.phone);
},
sendVoice() {
return this.sendVoiceFunc(this.phone);
},
handlePwdChange(v: string) {
this.pwd = v;
},
handleClickConfirm() {},
},
computed: {
phoneValid(): boolean {
return phoneConfig.validate(this.phone);
},
getConfirmDisabled(): boolean {
return !(
phoneConfig.validate(this.phone) &&
codeConfig.validate(this.code) &&
pwdConfig.validate(this.pwd)
);
},
},
});
</script>
<style>
</style>
\ No newline at end of file
<template>
<div class="px-5">
<pwd-find
:sendSmsFunc="sendSmsFunc"
:sendVoiceFunc="sendVoiceFunc"
:setPwdFunc="setPwdFunc"
/>
</div>
</template>
<script lang="ts">
import Vue, { VueConstructor } from "vue";
import PwdFind from "./PwdFind.vue";
export default (
Vue as VueConstructor<
Vue & {
sendSmsFunc: any;
setPwdFunc: any;
sendVoiceFunc: any;
}
>
).extend({
components: { PwdFind },
inject: ["sendSmsFunc", "setPwdFunc", "sendVoiceFunc"],
});
</script>
<style>
</style>
\ No newline at end of file
<template>
<div class="text-font-white">
<div class="text-font-white text-2xl mt-16">修改登录密码</div>
<div class="mt-8 mb-9">正在为 {{ phone }} 修改登录密码</div>
<transition name="fade" mode="out-in">
<Input
v-if="modifyWay === eModifyWay.ORIGINAL_PWD"
key="1"
:placeholder="pwdConfig.placeholder3"
:maxlength="pwdConfig.maxLen"
:value="pwd"
:type="pwdConfig.type"
@change="handlePwdChange"
:showEye="false"
></Input>
<CodeInput
v-else-if="modifyWay === eModifyWay.CODE"
:placeholder="codeConfig.placeholder"
:maxlength="codeConfig.maxLen"
:value="code"
:type="codeConfig.type"
:handleChange="handleCodeChange"
:phone="phone"
:sendSmsFunc="sendSmsFunc"
:sendVoiceFunc="sendVoiceFunc"
:phoneValid="phoneValid"
>
</CodeInput>
</transition>
<Input
:placeholder="pwdConfig.placeholder2"
:maxlength="pwdConfig.maxLen"
:value="pwd2"
:type="pwdConfig.type"
@change="handlePwdChange2"
></Input>
<LoginButton
class="mt-20"
text="确定"
:disabled="getConfirmDisabled"
:loading="loading"
@click="handleClickConfirm"
></LoginButton>
<div class="mt-5 text-center text-font-blue text-sm">
<transition name="fade" mode="out-in">
<div
key="1"
v-if="modifyWay === eModifyWay.ORIGINAL_PWD"
@click="transterModifyWay(eModifyWay.CODE)"
>
验证码修改
</div>
<div key="2" v-else @click="transterModifyWay(eModifyWay.ORIGINAL_PWD)">
原密码修改
</div>
</transition>
</div>
</div>
</template>
<script lang="ts">
import Vue, { PropType } from "vue";
import Input from "@/components/common/Input/index.vue";
import { pwdConfig, codeConfig, phoneConfig } from "../Login/const";
import LoginButton from "../Login/components/LoginButton/index.vue";
import { tModifyPwdFunc, eModifyWay } from "./types";
import { tSendSmsFunc, tSendVoiceFunc } from "../Login/types";
import CodeInput from "../Login/components/CodeInput/index.vue";
export default defineComponent({
props: {
phone: {
required: true,
type: String,
},
modifyPwdFunc: {
type: Function as PropType<tModifyPwdFunc>,
required: true,
},
sendSmsFunc: {
type: Function as PropType<tSendSmsFunc>,
required: true,
},
sendVoiceFunc: {
type: Function as PropType<tSendVoiceFunc>,
required: false,
},
},
components: {
Input,
LoginButton,
CodeInput,
},
data() {
return {
pwdConfig,
codeConfig,
pwd: "",
pwd2: "",
code: "",
loading: false,
eModifyWay,
modifyWay: eModifyWay.ORIGINAL_PWD,
};
},
computed: {
getConfirmDisabled(): boolean {
if (this.modifyWay === eModifyWay.ORIGINAL_PWD) {
return (
!(pwdConfig.validate(this.pwd) && pwdConfig.validate(this.pwd2)) ||
this.loading
);
} else if (this.modifyWay === eModifyWay.CODE) {
return (
!(pwdConfig.validate(this.pwd2) && codeConfig.validate(this.code)) ||
this.loading
);
} else {
return false;
}
},
phoneValid(): boolean {
return phoneConfig.validate(this.phone);
},
},
methods: {
handleCodeChange(v: string) {
this.code = v;
},
handlePwdChange(v: string) {
this.pwd = v;
},
transterModifyWay(way: eModifyWay) {
this.modifyWay = way;
},
handlePwdChange2(v: string) {
this.pwd2 = v;
},
async handleClickConfirm() {
const { pwd, pwd2 } = this;
this.loading = true;
// ??????
try {
if (this.modifyWay === eModifyWay.ORIGINAL_PWD) {
await this.modifyPwdFunc(this.phone, this.pwd, this.pwd2);
} else if (this.modifyWay === eModifyWay.CODE) {
}
} catch (err) {}
this.loading = false;
},
},
});
</script>
<style>
</style>
\ No newline at end of file
<template>
<div class="px-5">
<pwd-modify
:phone="$route.query.phone"
:modifyPwdFunc="modifyPwdFunc"
:sendSmsFunc="sendSmsFunc"
/>
</div>
</template>
<script lang="ts">
import Vue, { VueConstructor } from "vue";
import PwdModify from "./PwdModify.vue";
export default (
Vue as VueConstructor<
Vue & {
modifyPwdFunc: any;
sendVoiceFunc: any;
sendSmsFunc: any;
}
>
).extend({
components: { PwdModify },
inject: ["modifyPwdFunc", "sendSmsFunc"],
});
</script>
<style>
</style>
\ No newline at end of file
export type tModifyPwdFunc = (phone: string, originalPwd: string, newPwd: string) => Promise<any>
export enum eModifyWay {
ORIGINAL_PWD,
CODE
}
\ No newline at end of file
<template>
<div>
<div class="text-font-white text-2xl mt-16">设置密码</div>
<div class="text-font-white mt-8">验证码已发送至 +86 {{ phone }}</div>
<CodeInput
class="mt-8"
:placeholder="codeConfig.placeholder"
:maxlength="codeConfig.maxLen"
:value="code"
:type="codeConfig.type"
:handleChange="handleCodeChange"
:phone="phone"
:sendSmsFunc="sendSmsFunc"
:sendVoiceFunc="sendVoiceFunc"
:phoneValid="phoneValid"
:sendSmsAuto="true"
/>
<Input
:placeholder="pwdConfig.placeholder2"
:maxlength="pwdConfig.maxLen"
:value="pwd"
:type="pwdConfig.type"
@change="handlePwdChange"
>
<template #button> </template>
</Input>
<LoginButton
class="mt-20"
text="确定"
:loading="loading"
:disabled="getConfirmDisabled"
@click="handleClickConfirm"
></LoginButton>
</div>
</template>
<script lang="ts">
import Vue, { PropType } from "vue";
import CodeInput from "../Login/components/CodeInput/index.vue";
import { codeConfig, phoneConfig, pwdConfig } from "../Login/const";
import { tSendSmsFunc, tSendVoiceFunc } from "../Login/types";
import Input from "@/components/common/Input/index.vue";
import LoginButton from "../Login/components/LoginButton/index.vue";
import { tSetPwdFunc } from "./types";
export default defineComponent({
components: { CodeInput, Input, LoginButton },
props: {
phone: {
type: String,
default: "",
},
sendSmsFunc: {
type: Function as PropType<tSendSmsFunc>,
required: true,
},
sendVoiceFunc: {
type: Function as PropType<tSendVoiceFunc>,
},
setPwdFunc: {
type: Function as PropType<tSetPwdFunc>,
required: true,
},
},
data() {
return {
codeConfig,
pwdConfig,
code: "",
pwd: "",
loading: false,
};
},
computed: {
getConfirmDisabled(): boolean {
return (
!(codeConfig.validate(this.code) && pwdConfig.validate(this.pwd)) ||
!this.phoneValid
);
},
phoneValid(): boolean {
return phoneConfig.validate(this.phone);
},
},
methods: {
async handleClickConfirm() {
const { phone, code, pwd } = this;
this.loading = true;
try {
await this.setPwdFunc(phone, code, pwd);
} catch (err) {}
this.loading = false;
},
handleCodeChange(v: string) {
this.code = v;
},
sendSms() {
return this.sendSmsFunc(this.phone);
},
sendVoice() {
return this.sendVoiceFunc(this.phone);
},
handlePwdChange(value: string) {
this.pwd = value;
},
},
});
</script>
<style>
</style>
\ No newline at end of file
<template>
<div class="px-5">
<pwd-setting
:phone="$route.query.phone"
:sendSmsFunc="sendSmsFunc"
:setPwdFunc="setPwdFunc"
/>
</div>
</template>
<script lang="ts">
import PwdSetting from "./PwdSetting.vue";
import Vue, { VueConstructor } from "vue";
export default (
Vue as VueConstructor<
Vue & {
sendSmsFunc: any;
setPwdFunc: any;
}
>
).extend({
components: { PwdSetting },
inject: ["sendSmsFunc", "setPwdFunc"],
methods: {},
});
</script>
/* 设置密码 */
export type tSetPwdFunc = (phone: string, code: string, pwd: string) => Promise<any>
\ No newline at end of file
<template>
<div class="bg-font-black">
<router-view></router-view>
</div>
</template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
export default defineComponent({
provide(): object {
return {
sendSmsFunc: this.sendSmsFunc,
accountStatusCheckFunc: this.accountStatusCheckFunc,
registerFunc: this.registerFunc,
loginByCodeFunc: this.loginByCodeFunc,
loginByPwdFunc: undefined,
setPwdFunc: this.setPwdFunc,
modifyPwdFunc: this.modifyPwdFunc,
};
},
methods: {
async sendSmsFunc(phone: string) {
// await this.$service.userService.getVerificationCode(phone, "1");
},
async accountStatusCheckFunc(phone: string) {
// const isRegisterd = await this.$service.userService.isRegisterd(phone);
// if (!isRegisterd) {
// return eAccountType.NO_REG;
// } else {
// const isPwdSet = await this.$service.userService.isPwdSet(phone);
// return isPwdSet ? eAccountType.REG_PDSET : eAccountType.REG_NOPD;
// }
},
async registerFunc(phone: string, code: string) {
// const ret = await this.$service.userService.loginAndSign({
// codetype: "sms",
// telephone: phone,
// verificationCode: code,
// });
// if (ret) {
// const { Authorization, user } = ret;
// token.setToken(Authorization);
// userMsg.setUserMsg(user);
// this.$router.push({
// name: "Home",
// });
// }
},
async loginByCodeFunc(phone: string, code: string) {
return this.registerFunc(phone, code);
},
async loginByPwdFunc(phone: string, pwd: string) {
console.log(phone, pwd);
},
async setPwdFunc(phone: string, code: string, pwd: string) {
console.log(phone, code, pwd);
this.$router.push({
name: "Home",
});
return 1;
},
async modifyPwdFunc(phone: string, originalPwd: string, newPwd: string) {
console.log(phone, originalPwd, newPwd);
},
},
});
</script>
<style lang="less">
</style>
<template></template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
export default defineComponent({});
</script>
\ No newline at end of file
This diff is collapsed.
<template>
<div class="flex items-center">
<div
class="h-9 flex-row flex items-center bg-white px-2.5"
style="border-radius: 9px"
v-if="active"
>
<Icon color="#4E61C9" :name="iconName" size="23" />
<span class="ml-2 tabText text-app-blue">{{ tabName }}</span>
</div>
<div v-else>
<Icon color="#A3ABE0" :name="iconName" size="23" />
</div>
</div>
</template>
<script>
import Icon from "@/components/common/Icon";
export default {
props: ["tabName", "iconName", "active"],
components: {
Icon,
},
};
</script>
<style>
.tabText {
font-size: 10px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #3e4faf;
line-height: 14px;
}
</style>
\ No newline at end of file
<template>
<div
class="h-16 flex bg-app-blue items-center mx-2.5 overflow-hidden"
style="border-radius: 19px"
>
<div class="flex-row flex justify-around w-full h-full">
<div
v-for="item in list"
class="flex items-center justify-center"
:class="
activeTabRouteName === item.routeName ? 'little-grow' : 'flex-grow '
"
:key="item.name"
@click="clickTabItem(item)"
>
<TabItem
:tabName="item.name"
:iconName="item.icon"
:active="activeTabRouteName === item.routeName"
/>
</div>
</div>
</div>
</template>
<script lang="ts">
import Icon from "@/components/common/Icon.vue";
import TabItem from "./TabItem.vue";
import tabList from "../../tabList";
import { defineComponent } from "vue";
export default defineComponent({
components: {
Icon,
TabItem,
},
props: ["list", "activeTabRouteName"],
methods: {
clickTabItem(item: typeof tabList[0]) {
this.$router.push({
name: item.routeName,
});
},
},
});
</script>
<style scoped>
.wrap25 {
z-index: 39;
height: 60px;
align-self: center;
justify-content: center;
align-items: flex-start;
}
.box3 {
z-index: 40;
height: 35px;
border-radius: 9px;
background-color: rgba(255, 255, 255, 1);
width: 80px;
justify-content: center;
align-items: center;
}
.layer5 {
z-index: auto;
width: 54px;
height: 21px;
justify-content: space-between;
}
.label12 {
z-index: 68;
width: 22px;
height: 21px;
}
.little-grow {
flex-grow: 0.5;
}
.info12 {
z-index: 67;
width: 26px;
display: block;
overflow-wrap: break-word;
color: rgba(62, 79, 175, 1);
font-size: 10px;
font-family: PingFangSC-Medium;
white-space: nowrap;
line-height: 14px;
text-align: center;
margin-top: 4px;
}
.icon8 {
z-index: 59;
width: 25px;
height: 22px;
margin: 6px 0 0 51px;
}
.label13 {
z-index: 41;
width: 22px;
height: 23px;
margin: 6px 0 0 54px;
}
.label14 {
z-index: 48;
width: 22px;
height: 22px;
margin: 6px 0 0 58px;
}
</style>
\ No newline at end of file
<template>
<van-swipe class="my-swipe" indicator-color="#3E4FAF">
<van-swipe-item class="flex justify-center swpiItem"
><FnsCard3 />
</van-swipe-item>
<van-swipe-item class="flex justify-center swpiItem"
><FnsCard3
/></van-swipe-item>
<van-swipe-item class="flex justify-center swpiItem"
><FnsCard3
/></van-swipe-item>
</van-swipe>
</template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
import { Swipe, SwipeItem } from "vant";
import FnsCard3 from "@/components/FnsCard3/index.vue";
export default defineComponent({
components: {
"van-swipe": Swipe,
"van-swipe-item": SwipeItem,
FnsCard3,
},
});
</script>
<style lang="less" scoped>
.my-swipe /deep/ .van-swipe__indicator {
background-color: #e7e7e7;
opacity: 1;
}
.swpiItem {
height: 270px;
}
</style>
\ No newline at end of file
This diff is collapsed.
<template>
<div class="page flex-col">
<div class="main1 flex-col">
<div class="outer1 flex-col">
<div class="box2 flex-row justify-between">
<div class="flex items-center">
<icon
class="icon2"
name="icon-gouxuanyangshi"
color="#A7B2E3"
size="17"
/>
<span class="word2">中低风险</span>
</div>
<div class="flex items-center">
<icon
class="icon2"
name="icon-gouxuanyangshi"
color="#A7B2E3"
size="17"
/>
<span class="word3">风格稳健</span>
</div>
<div class="flex items-center">
<icon
class="icon2"
name="icon-gouxuanyangshi"
color="#A7B2E3"
size="17"
/>
<span class="txt1">长期持有增值</span>
</div>
</div>
<div class="box3 flex-col"><span class="word4">精选理财</span></div>
</div>
<MainFnsSwip class="relative z-10 mainfnsswip" />
<GroupTitle title="精选理财" subtitle="安稳省心 爆款甄选" />
<FnsCard4 v-for="n in 3" :key="n" :data="n" />
</div>
</div>
</template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
import Icon from "@/components/common/Icon.vue";
import FnsCard3 from "@/components/FnsCard3/index.vue";
import GroupTitle from "@/components/GroupTitle/index.vue";
import MainFnsSwip from "./Components/MainFnsSwip/index.vue";
import FnsCard4 from "@/components/FnsCard4/index.vue";
export default defineComponent({
components: {
Icon,
FnsCard3,
MainFnsSwip,
GroupTitle,
FnsCard4,
},
data() {
return {
constants: {},
};
},
methods: {},
});
</script>
<style lang="less" scoped>
@import "./index.less";
.mainfnsswip {
margin-top: -130px;
}
</style>
\ No newline at end of file
<template>
<div class="flex flex-wrap justify-between">
<div v-for="app in appList" :key="app.name" class="w-1/4 mb-5 text-center">
<div
class="
w-16
h-16
bg-white
app-container
mx-auto
flex
items-center
justify-center
"
>
<Icon :name="app.icon" :color="app.color" size="25" />
</div>
<div class="mt-2.5 app-name">{{ app.name }}</div>
</div>
</div>
</template>
<script lang="ts">
import Icon from "@/components/common/Icon.vue";
import { defineComponent } from "vue";
export default defineComponent({
components: { Icon },
props: ["appList"],
});
</script>
<style scoped>
.app-container {
box-shadow: 0px 2px 13px 0px rgba(240, 246, 252, 1);
border-radius: 20px;
}
.app-name {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #1b1f37;
}
</style>
\ No newline at end of file
<template>
<van-swipe class="my-swipe" :autoplay="3000" indicator-color="white">
<van-swipe-item v-for="(image, index) in bannerUrls" :key="index">
<vantImage fit="contain" class="h-36 w-full" :src="image" />
</van-swipe-item>
</van-swipe>
</template>
<script lang="ts">
import { defineComponent } from "vue";
import { Image } from "vant";
export default defineComponent({
components: {
vantImage: Image,
},
props: {
bannerUrls: {
type: Array,
default() {
return [
"https://img01.yzcdn.cn/vant/apple-1.jpg",
"https://img01.yzcdn.cn/vant/apple-2.jpg",
];
},
},
},
});
</script>
<style scoped lang="less">
.my-swipe .van-swipe-item {
color: #fff;
font-size: 20px;
line-height: 100px;
text-align: center;
background-color: #818c92;
}
</style>
<template>
<div class="bd4 overflow-hidden block1" style="width: 31%">
<p class="txt6 overflow-ellipsis overflow-hidden" style="margin-top: 30px">
{{ item.lanhutext0 }}
</p>
<p class="word10 overflow-ellipsis overflow-hidden">
{{ item.lanhutext1 }}
</p>
<p class="word11 overflow-ellipsis overflow-hidden">
{{ item.lanhutext2 }}
</p>
<p class="txt7 overflow-ellipsis overflow-hidden">{{ item.lanhutext3 }}</p>
</div>
</template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
export default defineComponent({
props: ["item"],
});
</script>
<style scoped>
.bd4 {
z-index: auto;
height: 110px;
}
.block1 {
height: 160px;
border-radius: 20px;
background-color: rgba(255, 255, 255, 1);
width: 105px;
justify-content: flex-end;
padding-bottom: 20px;
align-items: center;
}
.txt6 {
z-index: 121;
display: block;
overflow-wrap: break-word;
color: rgba(27, 31, 55, 1);
font-size: 14px;
letter-spacing: 0.1679999977350235px;
white-space: nowrap;
line-height: 20px;
text-align: center;
align-self: center;
}
.word10 {
z-index: 122;
display: block;
overflow-wrap: break-word;
color: rgba(141, 146, 175, 1);
font-size: 12px;
letter-spacing: 0.14399999380111694px;
white-space: nowrap;
line-height: 17px;
text-align: center;
margin-top: 5px;
}
.word11 {
z-index: 119;
display: block;
overflow-wrap: break-word;
color: rgba(240, 58, 48, 1);
font-size: 20px;
letter-spacing: 0.23999999463558197px;
font-family: PingFangSC-Semibold;
white-space: nowrap;
line-height: 28px;
text-align: center;
align-self: center;
margin-top: 20px;
}
.txt7 {
z-index: 120;
display: block;
overflow-wrap: break-word;
color: rgba(141, 146, 175, 1);
font-size: 12px;
letter-spacing: 0.14399999380111694px;
white-space: nowrap;
line-height: 17px;
text-align: center;
align-self: center;
margin-top: 3px;
}
</style>
\ No newline at end of file
<template>
<van-notice-bar
left-icon="volume-o"
:scrollable="false"
background="white"
style="border-radius: 24px"
color="#1B1F37"
class="mx-3.5 wrap11"
>
<template #left-icon>
<Icon name="icon-tongzhi" color="#1B1F37" class="mr-2" />
</template>
<van-swipe
vertical
class="notice-swipe"
:autoplay="3000"
:show-indicators="false"
>
<!-- <van-swipe-item>内容 1</van-swipe-item> -->
<!-- <van-swipe-item>内容 2</van-swipe-item> -->
<van-swipe-item class="overflow-ellipsis overflow-hidden"
>内容
3asdflkkllllllllllllllllllllllllllllllllllll3asdflkkllllllllllllllllllllllllllllllllllll3asdflkkllllllllllllllllllllllllllllllllllll</van-swipe-item
>
</van-swipe>
</van-notice-bar>
</template>
<script lang="ts">
import Icon from "@/components/common/Icon.vue";
import Vue, {defineComponent} from "vue";
import { NoticeBar, Swipe, SwipeItem } from "vant";
export default defineComponent({
components: {
Icon,
"van-swipe": Swipe,
"van-swipe-item": SwipeItem,
},
});
</script>
<style>
.notice-swipe {
height: 40px;
line-height: 40px;
}
.layer3 {
z-index: auto;
height: 17px;
justify-content: space-between;
}
.wrap11 {
height: 35px;
border-radius: 17.5px 17.5px 17.5px 17.5px;
border-width: 1px;
border: 1px solid rgba(255, 255, 255, 1);
background-color: rgba(255, 255, 255, 1);
justify-content: center;
padding: 0 14px;
}
.label7 {
z-index: 12;
width: 16px;
height: 14px;
margin-top: 2px;
}
.word7 {
z-index: 11;
display: block;
overflow-wrap: break-word;
color: rgba(27, 31, 55, 1);
font-size: 12px;
letter-spacing: 0.14399999380111694px;
white-space: nowrap;
line-height: 17px;
}
</style>
\ No newline at end of file
export default [
{
name: '贷款服务',
icon: 'icon-daikuan',
color: '#44D392',
},
{
name: '理财产品',
icon: 'icon-licaichanpin',
color: '#FF9534',
},
{
name: '精彩活动',
icon: 'icon-jingcaihuodong',
color: '#D886ED',
},
{
name: '网点服务',
icon: 'icon-wangdianfuwu',
color: '#00CEF7',
},
{
name: '政策支持',
icon: 'icon-zhengcezhichi',
color: '#D886ED',
},
{
name: '新闻动态',
icon: 'icon-xinwendongtai',
color: '#00CEF7',
},
{
name: '精彩直播',
icon: 'icon-jingcaizhibo',
color: '#0FCBA5',
},
{
name: '消息中心',
icon: 'icon-xiaoxizhongxin',
color: '#FF9566',
},
]
This diff is collapsed.
<template> <template>
<div class="home"> <div>
<img alt="Vue logo" src="../assets/logo.png"> <div class="home" v-for="n in 1000" :key="n">adsfads</div>
<HelloWorld msg="Welcome to Your Vue.js + TypeScript App"/>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import Vue, {defineComponent} from "vue";
import HelloWorld from '@/components/HelloWorld.vue'; // @ is an alias to /src
export default defineComponent({ export default defineComponent({
name: 'Home', components: {},
components: {
HelloWorld,
},
}); });
</script> </script>
<template>
<div class="mine">
mine
</div>
</template>
<script lang="ts">
import Vue, {defineComponent} from "vue";
export default defineComponent({
components: {},
});
</script>
<template>
<div class="h-screen bg-app-bg flex flex-col overflow-hidden">
<div class="flex-grow overflow-auto">
<router-view />
</div>
<TabBar
:list="tabList"
:activeTabRouteName="activeTabRouteName"
class="mt-1 flex-shrink-0"
/>
<div class="h-4 flex-shrink-0"></div>
</div>
</template>
<script>
import Vue, { defineComponent } from "vue";
import TabBar from "./Components/TabBar/index.vue";
import tabList from "./tabList";
export default defineComponent({
components: {
TabBar,
},
data() {
return {
tabList,
};
},
mounted() {},
computed: {
activeTabRouteName() {
return this.$route.name;
},
},
});
</script>
<style>
</style>
\ No newline at end of file
export default [
{
name: '首页',
routeName: 'Home',
icon: 'icon-shouye-tab-xuanze1',
},
{
name: '理财',
routeName: 'FinancialManagement',
icon: 'icon-licai-tabxuanze',
},
{
name: '贷款',
routeName: 'Loan',
icon: 'icon-daikuan-tab-xuanze',
},
{
name: '我的',
routeName: 'Mine',
icon: 'icon-wode-tabdianji',
},
]
const colors = require('tailwindcss/colors')
module.exports = {
purge: [
'./src/**/*.html',
'./src/**/*.js',
],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {},
colors: {
"transparent": "transparent",
"app-blue": "#3E4FAF",
"app-red": "#F03A30",
"app-white": "#F9FBFF",
"app-bg": "#F7F7FA",
"app-line": "#EAEAEB",
"app-main-txt": "#516379",
"app-minor-txt": "#EAEAEB",
black: colors.black,
white: colors.white,
gray: colors.coolGray,
red: colors.red,
yellow: colors.amber,
green: colors.emerald,
blue: colors.blue,
indigo: colors.indigo,
purple: colors.violet,
pink: colors.pink,
},
fontFamily: {
"pf-r": ["PingFangSC-Regular", "PingFang SC"],
}
},
variants: {
extend: {},
},
plugins: [],
}
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