Browse Source

合并master

pull/15/head
longchao 4 weeks ago
parent
commit
4ee309db04
  1. 2
      package.json
  2. 5
      src/App.vue
  3. 1
      src/assets/doctor_h5.svg
  4. 1
      src/assets/login_backImg.svg
  5. 117
      src/components/Header.vue
  6. 7
      src/main.js
  7. 49
      src/router/index.js
  8. 46
      src/utils/request.js
  9. 48
      src/views/HomeView.vue
  10. 17
      src/views/HosInformation.vue
  11. 296
      src/views/adminLogin.vue
  12. 382
      src/views/login.vue
  13. 38
      src/views/paymentMethod.vue

2
package.json

@ -15,7 +15,9 @@
"regenerator-runtime": "^0.14.1",
"vue": "^2.6.14",
"vue-clickaway": "^2.2.2",
"vue-qr": "^4.0.9",
"vue-router": "^3.5.1",
"vue-wxlogin": "^1.0.5",
"vuex": "^3.6.2"
},
"devDependencies": {

5
src/App.vue

@ -11,7 +11,7 @@
<SliderMenu v-if="showSidebar" :menuData="slidermenu" :customize="customize"></SliderMenu>
<el-container class="main-right-content">
<!-- 面包屑导航 -->
<Breadcrumb />
<Breadcrumb v-if="user"/>
<el-main class="app-content">
<global-loading>
<router-view />
@ -34,6 +34,7 @@ export default {
data() {
return {
isCollapse: true,
user:null
};
},
components: {
@ -46,6 +47,8 @@ export default {
...mapState(['hosMenuData','slidermenu','customize','showSidebar', 'showFooter', 'showHeader']) // VuexshowSidebar
},
mounted() {
this.user = localStorage.getItem('nick')
window.addEventListener('beforeunload', this.clearStorage);
},
beforeUnmount() {

1
src/assets/doctor_h5.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 357 KiB

1
src/assets/login_backImg.svg

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.3 MiB

117
src/components/Header.vue

@ -3,37 +3,121 @@
<div class="header-logo" @click="toHome">
<img src="../assets/header-logo.png" alt="">
</div>
<div class="header-right flex">
<!-- <div class="right-item">权限设置</div>
<div class="right-item">岗位设置</div> -->
<!-- <el-dropdown trigger="click">
<div class="header-right flex" v-if="headerShow">
<div
:class="['right-item', currentPath == item.path ? 'right-item-active' :'']"
v-for="(item,index) in routerNavList"
:key="index"
@click="goToPage(item.path)"
>
{{ item.name }}
</div>
<el-dropdown trigger="click">
<div class="right-item flex el-dropdown-link">
<img class="right-item-icon" src="../assets/header-icon.png" alt="">
<span>学术论文出版</span>
<img src="../assets/header-drop.svg" alt="">
<span>{{user}}</span>
<div class="img"></div>
</div>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item icon="el-icon-plus">黄金糕</el-dropdown-item>
<el-dropdown-item icon="el-icon-circle-plus">狮子头</el-dropdown-item>
<el-dropdown-item icon="el-icon-circle-plus-outline">螺蛳粉</el-dropdown-item>
<el-dropdown-item icon="el-icon-check">双皮奶</el-dropdown-item>
<el-dropdown-item icon="el-icon-circle-check">蚵仔煎</el-dropdown-item>
<el-dropdown-item><div @click="loginOut">退出</div></el-dropdown-item>
</el-dropdown-menu>
</el-dropdown> -->
</el-dropdown>
</div>
</div>
</template>
<script>
export default {
data(){
return{
user: '',
headerShow:false,
doctor_id:'',
authtoken:false,
currentPath:'',
routerNavList:[
// {
// name:'',
// path:'/doctorInformation'
// },
// {
// name:'',
// path:'/hospitalManage'
// },
// {
// name:'',
// path:'/paymentMethod'
// },
]
}
},
mounted(){
this.user = localStorage.getItem('user_name')
var user_type = localStorage.getItem('user_type')
if(!user_type || user_type == 'undefined') {
this.user = '超级管理员'
}else{
if(user_type && user_type != 'undefined') this.user = (user_type == 1?'医生':'助手') + this.user
}
this.doctor_id = localStorage.getItem('doctor_id')
this.authtoken = localStorage.getItem('authtoken')
if(this.authtoken){
this.headerShow = true
//
this.updateCurrentPath()
//
this.watchRouteChange()
}else{
this.headerShow = false
}
},
methods: {
toHome() {
this.$router.push({
path: '/'
})
},
goToPage(path) {
this.currentPath = path;
this.$router.push({
path: path + '?doctor_id=' + this.doctor_id
})
},
loginOut(){
localStorage.removeItem('token');
localStorage.removeItem('user_name');
localStorage.removeItem('authtoken');
localStorage.removeItem('user_type');
localStorage.removeItem('doctor_id');
this.$router.push('/login');
},
//
updateCurrentPath() {
const currentRoute = this.$route.path;
const matchedItem = this.routerNavList.find(item =>
currentRoute.startsWith(item.path)
);
if (matchedItem) {
this.currentPath = matchedItem.path;
} else {
this.currentPath = '';
}
},
//
watchRouteChange() {
this.$watch('$route', (to, from) => {
console.log(to,from,'====');
this.updateCurrentPath();
});
}
},
beforeDestroy() {
}
}
</script>
<style lang="scss" scoped>
.flex {
display: flex;
@ -56,8 +140,8 @@ export default {
}
.header-right {
width: 362px;
justify-content: flex-end;
gap:20px;
.el-dropdown-link {
cursor: pointer;
}
@ -72,12 +156,17 @@ export default {
transition: all .3s;
}
}
.right-item-active{
border-radius: 6px;
background: rgba(255, 255, 255, 0.4);
color: #006AFF;
transition: all .3s;
}
.el-dropdown .right-item{
padding: 0 10px;
cursor: pointer;
}
.right-item-icon {
width: 36px;
height: 36px;

7
src/main.js

@ -25,6 +25,13 @@ Vue.directive('clickaway', clickaway);
Vue.mixin(HeaderIcon)
Vue.use(PositionMessage)
window.issuper = true;
var user_type = localStorage.getItem('user_type')
if(user_type && user_type != 'undefined') window.issuper = false;
window.doctor_id = localStorage.getItem('doctor_id');
new Vue({
router,
store,

49
src/router/index.js

@ -5,10 +5,19 @@ import HomeView from '../views/HomeView.vue';
Vue.use(VueRouter)
const whiteSlideList = [ '/ui', '/hosInformation']; //侧边导航白名单
const blackHeaderList = ['/ErrorAccess']; //头部导航黑名单
const blackHeaderList = ['/ErrorAccess','/login']; //头部导航黑名单
const whiteFooterList = ['/','/doctorInformation' ,'/hosInformation','/addNewTreatment']; //底部白名单
const routes = [
{
path: '/login',
name: '登录',
component: () => import('../views/adminLogin.vue'),
meta: {
hideBreadcrumb: true, // 首页不显示面包屑
requiresAuth:false
}
},
{
path: '/',
name: '首页',
component: HomeView,
@ -18,6 +27,19 @@ const routes = [
}
},
{
path: '/hospitalManage',
name: '医院管理',
component: HomeView,
props:{
onlyHosFlag:true
},
meta: {
title: '医院管理',
hideBreadcrumb: true, // 首页不显示面包屑
requiresAuth:true
}
},
{
path: '/doctorInformation',
name: '医生信息',
component: () => import('../views/DoctorInformation.vue'),
@ -42,9 +64,6 @@ const routes = [
meta: {
title: '编辑医院',
breadcrumbParent: '医生信息' // 手动指定父级
// r如果想隐藏中间层级
// breadcrumbParent: '首页', // 跳过医生信息
// hideInBreadcrumb: true // 可选:隐藏当前项
}
},
{
@ -54,9 +73,6 @@ const routes = [
meta: {
title: '微信收款',
breadcrumbParent: '编辑医院' // 手动指定父级
// r如果想隐藏中间层级
// breadcrumbParent: '首页', // 跳过医生信息
// hideInBreadcrumb: true // 可选:隐藏当前项
}
},
@ -83,7 +99,8 @@ const routes = [
name: '收款方式',
meta: {
title: '收款管理',
hideBreadcrumb: true // 首页不显示面包屑
hideBreadcrumb: true, // 首页不显示面包屑
requiresAuth:true
}
},
{
@ -102,7 +119,22 @@ const router = new VueRouter({
base: process.env.BASE_URL,
routes
})
router.beforeEach((to, from, next) => {
// 检查本地存储是否有nick
const hasNick = localStorage.getItem('nick');
// 如果有nick且访问的是根路径,则重定向到/hospitalManage
if (hasNick && to.path === '/') {
next('/hospitalManage');
return;
}
// 如果没有nick且尝试访问需要认证的页面(如/hospitalManage),则重定向到首页
if (!hasNick && to.meta.requiresAuth) {
next('/');
return;
}
if (whiteSlideList.includes(to.path)) {
store.commit('SET_SIDEBAR', true); // 登录页面不显示侧边栏
} else {
@ -118,6 +150,7 @@ router.beforeEach((to, from, next) => {
} else {
store.commit('SET_HEADER', true); // 其他页面显示顶部
}
next();
});

46
src/utils/request.js

@ -15,10 +15,21 @@ const service = axios.create({
service.interceptors.request.use(
(config) => {
// 在发送请求之前做一些处理,例如添加 token
const token = localStorage.getItem("token");
if (token) {
config.headers["Auth"] = `${token}`;
// const token = localStorage.getItem("token");
const token = localStorage.getItem("authtoken");
const doctor_id = localStorage.getItem("doctor_id");
// 检查是否存在 token,如果不存在则跳转到登录页
if (!token && location.pathname != '/login' && location.href.indexOf('/login') == -1) {
// 可以根据需要决定是否提示用户
console.warn("未检测到登录信息,请重新登录");
window.location.href = "/login";
return Promise.reject(new Error("未登录"));
}
if (token) config.headers["Auth"] = `${token}`;
if (doctor_id) config.headers["DID"] = `${doctor_id}`;
return config;
},
(error) => {
@ -58,10 +69,19 @@ service.interceptors.response.use(
console.error("请求失败", error.message);
}
}
return Promise.reject(error);
}
);
function logout() {
localStorage.removeItem('authtoken')
localStorage.removeItem('doctor_id')
localStorage.removeItem('user_name')
localStorage.removeItem('user_type')
location.href = '/login'
}
/**
* 封装请求方法
* @param {string} method 请求方法 (GET, POST, PUT, DELETE )
@ -81,9 +101,13 @@ const request = (method, url, data = {}, config = {}) => {
...config,
});
res.then(response => {
if(response && response.msg && response.msg.indexOf('非法操作') > -1) {
localStorage.removeItem('authtoken')
location.href = '/ErrorAccess'
if(response && response.msg && response.msg.indexOf('您没有访问权限~~~') > -1) {
location.href = '/'
return;
}
if(response && response.msg && (response.msg.indexOf('非法操作') > -1 || response.code == 40002)) {
logout()
return;
}
}).catch(error => {
@ -101,9 +125,13 @@ const request = (method, url, data = {}, config = {}) => {
});
respost.then(response => {
if(response && response.msg && response.msg.indexOf('非法操作') > -1) {
localStorage.removeItem('authtoken')
location.href = '/ErrorAccess'
if(response && response.msg && response.msg.indexOf('您没有访问权限~~~') > -1) {
location.href = '/'
return;
}
if(response && response.msg && (response.msg.indexOf('非法操作') > -1 || response.code == 40002)) {
logout()
return;
}
}).catch(error => {

48
src/views/HomeView.vue

@ -1,7 +1,7 @@
<template>
<div class="min-width pagePadding " style="background: #F5F7FA;" v-if="pageShow">
<div class="doctor-list-wrap ">
<p class="pageTitle">医生列表</p>
<p class="pageTitle">{{issuper ? '医院管理' :'医生列表'}}</p>
<el-form>
<div class="selectAllTable-wrap flex-between mt32">
<div class="left flex">
@ -16,16 +16,20 @@
@click="batchOperate('1')">
批量启用</GuipButton>
</div>
<div class="right flex">
<div class="right" v-if="!issuper">
<GuipButton type="system" size="form" @click="addHospital(false)">添加医院</GuipButton>
</div>
<div class="right flex" v-else>
<span>搜索医生</span>
<GuipInput ref="GuipInput" style="margin:0 24px 0 12px" width="280px" height="32px"
placeholder="输入姓名" @blur="inputBlur" v-model="doctorName" />
<GuipButton @click="addDoctor" size="form">新增医生</GuipButton>
</div>
</div>
<div class="tableList mt32" v-for="(item, index) in doctorList" :key="index">
<div class="top flex-between mb24">
<div class="top flex-between mb24" v-if="issuper">
<div class="left left1 flex">
<el-checkbox @change="handleCheckAllChange(index)" v-model="item.checked"></el-checkbox>
<el-avatar :src="item.avator" v-if="item.avator"></el-avatar>
@ -88,8 +92,7 @@
</template>
</el-table-column>
</GuipTable>
<PaymentMethod :list="payList[item.id] ? payList[item.id] : []" @updatePayStatus="updatePayStatus" :depart_id="item.id" :doctor_id="item.id"/>
<PaymentMethod :list="payList[item.id] ? payList[item.id] : []" @updatePayStatus="updatePayStatus" :depart_id="item.id" :doctor_id="item.id" v-if="!onlyHosFlag"/>
</div>
</el-form>
</div>
@ -107,6 +110,7 @@ import { mapState } from 'vuex';
import PaymentMethod from '@/views/paymentMethod.vue';
export default {
props:['onlyHosFlag'],
data() {
return {
list: {
@ -143,7 +147,8 @@ export default {
allChecked: false,
pageShow:false,
doctorIds:[],
payList:[]
payList:false,
issuper:false
}
},
components: {
@ -158,18 +163,27 @@ export default {
// CustomDropdown
},
created() {
const { authtoken } = this.$route.query;
const { authtoken, did, type, name} = this.$route.query;
if(authtoken) {
localStorage.setItem('authtoken', authtoken);
localStorage.setItem('authtoken', decodeURIComponent(authtoken));
localStorage.setItem('doctor_id', did);
localStorage.setItem('user_type', type);
localStorage.setItem('user_name', name);
location.href = '/'
return;
}
store.commit('SET_PAGENAME', '医生管理'); //
},
mounted() {
this.issuper = window.issuper
store.commit('SET_CUSTOMIZE', false);
store.commit('SET_SLIDER_MENU', 'menuData');
this.getInitData()
if(this.onlyHosFlag)return
// --
this.getBindpayList()
},
computed: {
...mapState(['menuData']) // VuexshowSidebar
@ -295,7 +309,7 @@ export default {
})
},
onSwitchChange1(row) {
console.log(row, '------flag');
// console.log(row, '------flag');
row.status = row.status == 0 ? 1 : 0;
this.$http('POST', '/api/admin/depart_mutil_option', {
depart_index_ids:row.id,
@ -315,7 +329,7 @@ export default {
this.$set(this.doctorList, row)
},
batchOperate(status) {
console.log(this.tableSelections,'this.tableSelections----');
// console.log(this.tableSelections,'this.tableSelections----');
if(!this.tableSelections || this.tableSelections.length <= 0) {
this.$message.error('未选择要'+(status == '0' ? '禁用':'启用')+'的科室')
return;
@ -388,9 +402,21 @@ export default {
})
},
addHospital(item) {
var docotr_id = window.doctor_id
if(item) {
docotr_id = item.id
}
this.$router.push({
name: '医院信息',
query: { doctor_id: docotr_id }
})
},
addHospitalUser(){
// id token
let id = this.doctor_id;
this.$router.push({
name: '医院信息',
query: { doctor_id: item.id }
query: { doctor_id: id }
})
},
editDoctor(item) {

17
src/views/HosInformation.vue

@ -1001,7 +1001,6 @@ export default {
this.depart_id = depart_id;
this.doctor_id = doctor_id;
await this.fetchDoctorData()
console.log(this.doctor_id)
await this.getAreaData()
this.fetchPackData()
this.fetchProjectData()
@ -1020,10 +1019,12 @@ export default {
this.doctor_id = newVal.doctor_id;
this.depart_id = newVal.depart_id;
this.getAreaData();
this.fetchDoctorData();
this.fetchPackData();
this.fetchProjectData();
this.geHosAdress();
if(this.depart_id) {
this.fetchDoctorData();
this.fetchPackData();
this.fetchProjectData();
this.geHosAdress();
}
}
}
},
@ -2661,6 +2662,12 @@ export default {
depart_id: this.depart_id,
doctor_id: this.doctor_id
}).then(response => {
if(response.code != 0) {
this.$Message.error(response.msg);
// location.href = '/'
return;
}
this.form = {
...this.form, ...response.data,
'morning_worktime': response.data.morning_worktime ? response.data.morning_worktime.split('-') : '',

296
src/views/adminLogin.vue

@ -0,0 +1,296 @@
<template>
<div class="index_loginPage__K_bGK login-wrap">
<div class="index_banner__1d8CU">
<div class="index_rootContainer">
<b class="title">扫码登录</b>
<p class="sub_title mt32">打开 <b>微信</b> 扫码登录</p>
<div class="wxlogin-qrcode-box mb32" v-if="status == 'waiting'">
<Wxlogin
v-if="appid && redirect_uri"
:appid="appid"
:redirect_uri="redirect_uri"
scope="snsapi_login"
:state="state"
height="186px"
href="data:text/css;base64,LmltcG93ZXJCb3ggLnFyY29kZSB7d2lkdGg6IDE4OHB4O2JvcmRlcjpub25lO21hcmdpbi10b3A6MHB4O30KLmltcG93ZXJCb3ggLnRpdGxlIHtkaXNwbGF5OiBub25lO30KLmltcG93ZXJCb3ggLmluZm8ge3dpZHRoOiAxODhweDtkaXNwbGF5Om5vbmU7fQouc3RhdHVzX2ljb24ge2Rpc3BsYXk6IG5vbmV9Ci5pbXBvd2VyQm94IC5zdGF0dXMge3RleHQtYWxpZ246IGNlbnRlcjt9Ci53ZWJfcXJjb2RlX3R5cGVfaWZyYW1le2hlaWdodDoxODZweDt9Ci53ZWJfcXJjb2RlX3N3aXRjaF93cnAuanNfc3dpdGNoVG9GYXN0X3dycHttYXJnaW4tdG9wOjBweCAhaW1wb3J0YW50O2NvbG9yOiAjOEE5MDk5ICFpbXBvcnRhbnQ7fQoud2ViX3FyY29kZV9zd2l0Y2hfd3JwLmpzX3N3aXRjaFRvRmFzdF93cnAgYnV0dG9ue2NvbG9yOiAjOEE5MDk5ICFpbXBvcnRhbnQ7Y3Vyc29yOnBvaW50ZXI7fQoud2ViX3FyY29kZV9zd2l0Y2hfd3JwLmpzX3N3aXRjaFRvTm9ybWFsX3dycCBidXR0b257Y29sb3I6ICM4QTkwOTkgIWltcG9ydGFudDtjdXJzb3I6cG9pbnRlcjt9"
></Wxlogin>
</div>
<div class="refreshCode" v-if="status == 'expired'" @click="refreshCode">
<i class="el-icon-refresh"></i>
刷新二维码
</div>
<div class="attention gap10">
<el-checkbox v-model="checked"></el-checkbox>
<b>登录即代表同意 <a @click="jumpDoc">用户协议</a> <a @click="jumpDoc">隐私条款</a></b>
</div>
<p class="tip">若无账号请先联系客服注册</p>
</div>
</div>
<div class="style_footerWrapper">
<div class="left flex">
<img src="@/assets/doctor_h5.svg" alt="">
<div>
<b>手机端</b>
<p>微信扫码体验</p>
</div>
</div>
<div class="center">
<p><b>入驻指南</b>个人入驻 组织医院等入驻</p>
<p><b>人工咨询</b>扫左侧码进入手机端-我的-页面底部联系我们</p>
</div>
<div class="right">
<p><b>网站备案</b>© 2012-2025 something , <a href="">Inc. All rights 测试</a></p>
<p></p>
</div>
</div>
</div>
</template>
<script>
import Wxlogin from 'vue-wxlogin';
export default {
components: {
Wxlogin
},
data() {
return {
checked: true,
qrCodeUrl: 'https://example.com',
token: '',
status: 'expired',
loginTime:'',
appid:false,
redirectUri:false,
state:'zjadmin'
}
},
created(){
this.getLoginConfig()
},
methods: {
async getLoginConfig() {
this.status = 'waiting';
this.redirect_uri = '';
this.appid = '';
try {
await this.$http('POST', '/api/callback/get_admin_login_config').then(response => {
this.appid = response.data.appid
this.redirect_uri = response.data.redirect_uri
}).catch(error => {
console.error('生成二维码失败:', error);
this.status = 'error';
});
} catch (error) {
console.error('生成二维码失败:', error);
this.status = 'error';
}
},
handleLoginSuccess(data) {
this.status = 'confirmed';
this.userInfo = data.user_info;
this.loginTime = new Date().toLocaleString();
//
localStorage.setItem('authToken', data.auth_token);
localStorage.setItem('nick', JSON.stringify(data.nick));
localStorage.setItem('userInfo', JSON.stringify(data.user_info));
setTimeout(() => {
this.isLoggedIn = true;
this.$emit('login-success', data);
}, 1000);
},
}
}
</script>
<style lang="scss" scoped>
.index_banner__1d8CU {
align-items: center;
background-image: url(../assets/login_backImg.svg);
background-size: cover;
display: flex;
flex: 1 1;
justify-content: flex-end;
-webkit-transition: padding-right .5s;
transition: padding-right .5s;
width: 100%;
}
.index_rootContainer {
background: #fff;
border-radius: 16px;
box-shadow: 0 6px 40px 0 rgba(53, 76, 166, .08);
display: inline-block;
flex-shrink: 0;
height: 480px;
overflow: hidden;
width: 432px;
margin-right: 192px;
padding: 40px;
box-sizing: border-box;
display: flex;
flex-direction: column;
.title {
font-family: Microsoft YaHei;
font-size: 22px;
font-weight: bold;
line-height: normal;
text-align: center;
letter-spacing: 0.08em;
color: #1E2226;
}
.sub_title {
font-family: Microsoft YaHei;
font-size: 12px;
font-weight: normal;
line-height: normal;
letter-spacing: 0.08em;
color: #626573;
margin-top: 32px;
margin-bottom: 12px;
b{
font-weight: bold;
color: #1E2226;
}
}
.img {
width: 192px;
height: 192px;
background: #006AFF;
margin: 0 auto;
margin-bottom: 32px;
}
}
.attention,
.tip {
font-size: 12px;
font-weight: normal;
line-height: 13px;
letter-spacing: 0.08em;
color: #626573;
text-align: center;
display: flex;
justify-content: center;
b {
font-size: 12px;
font-weight: normal;
a {
text-decoration: none;
color: #006AFF;
cursor: pointer;
}
}
}
.attention {
margin-bottom: 12px;
}
.refreshCode {
width: 172px;
height: 172px;
background: rgba(255, 255, 255, 0.3);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
gap: 10px;
justify-content: center;
align-items: center;
color: #626573;
font-family: Arial, sans-serif;
font-weight: bold;
cursor: pointer;
margin: 20px auto;
i{
font-size: 28px;
}
}
@media(max-width: 1420px) {
.index_rootContainer {
margin-right: 102px;
}
}
.style_footerWrapper {
background: #f3f4f6;
display: flex;
align-items: center;
justify-content: center;
padding: 46px 49px;
width: 100%;
height: 192px;
box-sizing: border-box;
gap: 72px;
b {
font-size: 12px;
font-weight: bold;
line-height: 13px;
letter-spacing: 0.08em;
color: #1E2226;
}
.left {
gap: 12px;
div {
display: flex;
flex-direction: column;
gap: 8px;
text-align: left;
}
img {
width: 97px;
height: 100px;
}
}
.center,
.right {
display: flex;
flex-direction: column;
gap: 24px;
text-align: left;
p {
display: flex;
gap: 8px;
}
}
}
.style_iconWrapper__3qi7l {
flex-basis: 80px;
}
.index_loginPage__K_bGK {
display: flex;
flex-direction: column;
height: 100vh;
min-width: 1200px;
}
#ecomLoginForm {
height: 280px;
}
.wxlogin-qrcode-box{
div:first-of-type{
height: 214px;
}
}
</style>

382
src/views/login.vue

@ -0,0 +1,382 @@
<template>
<div class="index_loginPage__K_bGK login-wrap">
<div class="index_banner__1d8CU">
<div class="index_rootContainer">
<b class="title">扫码登录</b>
<p class="sub_title mt32">打开 <b>微信</b> 扫码登录</p>
<div class=" mb32" v-if="status == 'waiting'">
<vue-qr :text="qrCodeUrl" :size="192" :dot-scale="1"></vue-qr>
</div>
<div class="refreshCode" v-if="status == 'expired'" @click="refreshCode">
<i class="el-icon-refresh"></i>
刷新二维码
</div>
<!-- :logo-src="logoUrl"
:logo-scale="0.2" -->
<div class="attention gap10">
<el-checkbox v-model="checked"></el-checkbox>
<b>登录即代表同意 <a @click="jumpDoc">用户协议</a> <a @click="jumpDoc">隐私条款</a></b>
</div>
<p class="tip">若无账号请先联系客服注册</p>
</div>
</div>
<div class="style_footerWrapper">
<div class="left flex">
<img src="@/assets/doctor_h5.svg" alt="">
<div>
<b>手机端</b>
<p>微信扫码体验</p>
</div>
</div>
<div class="center">
<p><b>入驻指南</b>个人入驻 组织医院等入驻</p>
<p><b>人工咨询</b>扫左侧码进入手机端-我的-页面底部联系我们</p>
</div>
<div class="right">
<p><b>网站备案</b>© 2012-2025 something , <a href="">Inc. All rights 测试</a></p>
<p></p>
</div>
</div>
</div>
</template>
<script>
import VueQr from 'vue-qr'
export default {
components: {
VueQr
},
data() {
return {
checked: true,
qrCodeUrl: 'https://example.com',
token: '',
status: 'expired', // waiting, scanned, confirmed, expired, error
loginTime:'',
}
},
created(){
// this.generateQRCode()
},
beforeDestroy() {
this.clearTimers();
},
methods: {
jumpDoc() {
},
//
refreshCode() {
},
async generateQRCode() {
this.status = 'waiting';
this.qrCodeUrl = '';
try {
await this.$http('POST', '/api/admin/generate_qrcode', {
device_type: 'web',
timestamp: Date.now()
}).then(response => {
this.token = response.data.token;
this.qrCodeUrl = response.data.qr_code_url;
//
this.startPolling();
// 5
this.setExpireTimer();
}).catch(error => {
console.error('生成二维码失败:', error);
this.status = 'error';
});
} catch (error) {
console.error('生成二维码失败:', error);
this.status = 'error';
}
},
//
startPolling() {
this.clearTimers();
this.pollInterval = setInterval(async () => {
if (this.status === 'confirmed' || this.status === 'expired' || this.status === 'error') {
this.clearTimers();
return;
}
try {
await this.$http('POST', '/api/admin/check_scan_status', {
token: this.token
}).then(response => {
this.status = response.data.status;
if (response.data.status === 'scanned') {
//
setTimeout(() => {
this.handleLoginConfirm();
}, 2000);
} else if (response.data.status === 'confirmed') {
this.handleLoginSuccess(response.data);
} else if (response.data.status === 'expired') {
this.status = 'expired';
this.clearTimers();
}
}).catch(error => {
console.error('检查扫码状态失败:', error);
this.status = 'error';
this.clearTimers();
});
} catch (error) {
console.error('检查扫码状态失败:', error);
this.status = 'error';
this.clearTimers();
}
}, 2000);
},
//
async handleLoginConfirm() {
try {
await this.$http('POST', '/api/admin/confirm_login', {
token: this.token
}).then(response => {
if (response.data.success) {
this.handleLoginSuccess(response.data);
} else {
this.status = 'expired';
}
}).catch(error => {
console.error('登录确认失败:', error);
this.status = 'error';
});
} catch (error) {
console.error('登录确认失败:', error);
this.status = 'error';
}
},
//
handleLoginSuccess(data) {
this.status = 'confirmed';
this.userInfo = data.user_info;
this.loginTime = new Date().toLocaleString();
//
localStorage.setItem('authToken', data.auth_token);
localStorage.setItem('nick', JSON.stringify(data.nick));
localStorage.setItem('userInfo', JSON.stringify(data.user_info));
setTimeout(() => {
this.isLoggedIn = true;
this.$emit('login-success', data);
}, 1000);
},
//
setExpireTimer() {
this.expireTimer = setTimeout(() => {
if (this.status !== 'confirmed') {
this.status = 'expired';
this.clearTimers();
}
}, 5 * 60 * 1000); // 5
},
//
clearTimers() {
if (this.pollInterval) {
clearInterval(this.pollInterval);
this.pollInterval = null;
}
if (this.expireTimer) {
clearTimeout(this.expireTimer);
this.expireTimer = null;
}
},
}
}
</script>
<style lang="scss" scoped>
.index_banner__1d8CU {
align-items: center;
background-image: url(../assets/login_backImg.svg);
background-size: cover;
display: flex;
flex: 1 1;
justify-content: flex-end;
-webkit-transition: padding-right .5s;
transition: padding-right .5s;
width: 100%;
}
.index_rootContainer {
background: #fff;
border-radius: 16px;
box-shadow: 0 6px 40px 0 rgba(53, 76, 166, .08);
display: inline-block;
flex-shrink: 0;
height: 480px;
overflow: hidden;
width: 432px;
margin-right: 192px;
padding: 40px;
box-sizing: border-box;
display: flex;
flex-direction: column;
.title {
font-family: Microsoft YaHei;
font-size: 22px;
font-weight: bold;
line-height: normal;
text-align: center;
letter-spacing: 0.08em;
color: #1E2226;
}
.sub_title {
font-family: Microsoft YaHei;
font-size: 12px;
font-weight: normal;
line-height: normal;
letter-spacing: 0.08em;
color: #626573;
margin-top: 32px;
margin-bottom: 12px;
}
.img {
width: 192px;
height: 192px;
background: #006AFF;
margin: 0 auto;
margin-bottom: 32px;
}
}
.attention,
.tip {
font-size: 12px;
font-weight: normal;
line-height: 13px;
letter-spacing: 0.08em;
color: #626573;
text-align: center;
display: flex;
justify-content: center;
b {
font-size: 12px;
font-weight: normal;
a {
text-decoration: none;
color: #006AFF;
cursor: pointer;
}
}
}
.attention {
margin-bottom: 12px;
}
.refreshCode {
width: 172px;
height: 172px;
background: rgba(255, 255, 255, 0.3);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border-radius: 12px;
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
display: flex;
flex-direction: column;
gap: 10px;
justify-content: center;
align-items: center;
color: #626573;
font-family: Arial, sans-serif;
font-weight: bold;
cursor: pointer;
margin: 20px auto;
i{
font-size: 28px;
}
}
@media(max-width: 1420px) {
.index_rootContainer {
margin-right: 102px;
}
}
.style_footerWrapper {
background: #f3f4f6;
display: flex;
align-items: center;
justify-content: center;
padding: 46px 49px;
width: 100%;
height: 192px;
box-sizing: border-box;
gap: 72px;
b {
font-size: 12px;
font-weight: bold;
line-height: 13px;
letter-spacing: 0.08em;
color: #1E2226;
}
.left {
gap: 12px;
div {
display: flex;
flex-direction: column;
gap: 8px;
text-align: left;
}
img {
width: 97px;
height: 100px;
}
}
.center,
.right {
display: flex;
flex-direction: column;
gap: 24px;
text-align: left;
p {
display: flex;
gap: 8px;
}
}
}
.style_iconWrapper__3qi7l {
flex-basis: 80px;
}
.index_loginPage__K_bGK {
display: flex;
flex-direction: column;
height: 100vh;
min-width: 1200px;
}
#ecomLoginForm {
height: 280px;
}
</style>

38
src/views/paymentMethod.vue

@ -9,7 +9,7 @@
</div>
</div>
<el-form>
<GuipTable :tableData="payList" :loading="tableLoading">
<GuipTable :tableData="payList" >
<el-table-column prop="type" fixed="left" label="类型" width="140">
<template slot-scope="scope">
<div class="flex gap10">
@ -21,7 +21,13 @@
</el-table-column>
<el-table-column prop="company_short_name" label="公司简称" min-width="160px"></el-table-column>
<el-table-column prop="appid" label="账号" min-width="288px"></el-table-column>
<el-table-column prop="expires_time_desc" label="有效期" min-width="260px"></el-table-column>
<el-table-column prop="expires_time_desc" label="有效期" min-width="260px">
<template slot-scope="scope">
<div :class="scope.row.expires_time_desc=='已过期' || scope.row.expires_time_desc=='未授权'?' error':''">
{{scope.row.expires_time_desc}}
</div>
</template>
</el-table-column>
<el-table-column prop="status" label="上传证书" min-width="258px">
<template slot-scope="scope">
<div :class="'flex'+(scope.row.have_cert?'':' error')" v-if="scope.row.type == 2">
@ -104,16 +110,19 @@ export default {
},
watch:{
list: {
deep: true,
handler(newVal) {
console.log(newVal,'newVal=====');
this.payList = [...newVal];
this.tableLoading = false;
}
}
},
doctor_id(newVal){
if(newVal) this.doctorId = newVal
},
depart_id(newVal){
if(newVal) this.departId = newVal
},
},
created(){
const {doctor_id,depart_id } = this.$route.query;
@ -121,25 +130,8 @@ export default {
this.departId =depart_id;
this.doctorId =doctor_id;
}
console.log(this.doctor_id,'=doctor_id===');
},
mounted() {
if(this.doctor_id){
this.getBindpayList()
}
},
methods: {
async getBindpayList() {
await this.$http('POST', '/api/admin/get_pay_list', {
doctor_id: this.doctor_id,
depart_id: this.depart_id
}).then(response => {
this.payList = response.data;
}).catch(error => {
console.error(error, 'error')
})
},
handleEvent(data) {
this.isShowAddPay = data;
},

Loading…
Cancel
Save