| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530 |
- <template>
- <view class="apply-auth-page">
- <!-- 页面内挂载公共弹窗,保证 APP 真机可用 -->
- <AppConfirm ref="AppConfirm" />
- <scroll-view class="page-scroll" :scroll-y="true" :scroll-with-animation="true" :scroll-into-view="activeRowId" :style="{ '--kb-gap': kbGap + 'px' }">
- <!-- 顶部背景图:请将图片放入本页 images 目录,文件名仅使用字母/下划线 -->
- <view class="top-banner">
- <image class="top-bg-img" src="/static/images/bgtop.png" mode="widthFix" />
- <!-- 顶部信息区:logo、标题、说明(覆盖在背景图上) -->
- <view class="head">
- <image class="logo" :src="logoSrc" mode="widthFix" @error="onImageError" @load="onImageLoad" />
- <view class="tit-wrap">
- <text class="title">{{ pageTitle }}</text>
- <text class="desc">{{ pageDesc }}</text>
- </view>
- </view>
- </view>
- <!-- 信息表单卡片 -->
- <view class="form">
- <!-- 待审核状态或授权到期状态:只读展示 -->
- <view v-if="isReviewing || isExpired" class="review-mode">
- <view class="row">
- <view class="label-with-icon">
- <image class="label-icon" src="/static/images/hosp.png" mode="aspectFit" />
- <text class="label">医院</text>
- </view>
- <text class="value">{{ form.hospital }}</text>
- </view>
- <view class="row">
- <view class="label-with-icon">
- <image class="label-icon" src="/static/images/depart.png" mode="aspectFit" />
- <text class="label">科室</text>
- </view>
- <text class="value">{{ form.department }}</text>
- </view>
- <view class="row">
- <view class="label-with-icon">
- <image class="label-icon" src="/static/images/name.png" mode="aspectFit" />
- <text class="label">姓名</text>
- </view>
- <text class="value">{{ form.name }}</text>
- </view>
- <view class="row">
- <view class="label-with-icon">
- <image class="label-icon" src="/static/images/number.png" mode="aspectFit" />
- <text class="label">电话</text>
- </view>
- <text class="value">{{ form.phone }}</text>
- </view>
- <view class="row">
- <view class="label-with-icon">
- <image class="label-icon" src="/static/images/time.png" mode="aspectFit" />
- <text class="label">申请时间</text>
- </view>
- <text class="value">{{ applyTime }}</text>
- </view>
- <view class="row no-border">
- <view class="label-with-icon">
- <image class="label-icon" src="/static/images/remark.png" mode="aspectFit" />
- <text class="label">备注</text>
- </view>
- <text class="value">{{ form.remark }}</text>
- </view>
- </view>
- <!-- 申请状态:可输入 -->
- <view v-else>
- <view class="row" id="row-hospital"><text class="label">医院</text><input class="ipt" v-model="form.hospital" placeholder="请输入" placeholder-class="ph" @focus="onFocus('row-hospital','hospital')" @blur="onBlur" cursor-spacing="20" confirm-type="next" :confirm-hold="true" @confirm="onConfirmNext('hospital')" :focus="focusField==='hospital'" /></view>
- <view class="row" id="row-department"><text class="label">科室</text><input class="ipt" v-model="form.department" placeholder="请输入" placeholder-class="ph" @focus="onFocus('row-department','department')" @blur="onBlur" cursor-spacing="20" confirm-type="next" :confirm-hold="true" @confirm="onConfirmNext('department')" :focus="focusField==='department'" /></view>
- <view class="row" id="row-name"><text class="label">姓名</text><input class="ipt" v-model="form.name" placeholder="请输入" placeholder-class="ph" @focus="onFocus('row-name','name')" @blur="onBlur" cursor-spacing="20" confirm-type="next" :confirm-hold="true" @confirm="onConfirmNext('name')" :focus="focusField==='name'" /></view>
- <view class="row no-border" id="row-phone"><text class="label">电话</text><input class="ipt" v-model="form.phone" placeholder="请输入" placeholder-class="ph" @focus="onFocus('row-phone','phone')" @blur="onBlur" cursor-spacing="20" confirm-type="next" :confirm-hold="true" @confirm="onConfirmNext('phone')" :focus="focusField==='phone'" /></view>
- </view>
- </view>
- <!-- 备注独立卡片 - 只在申请状态显示 -->
- <view class="remark-card" v-if="!isReviewing && !isExpired">
- <view class="row no-border" id="row-remark">
- <text class="label">备注</text>
- <input class="ipt" v-model="form.remark" placeholder="请输入(选填)" placeholder-class="ph" @focus="onFocus('row-remark','remark')" @blur="onBlur" cursor-spacing="20" confirm-type="done" @confirm="onConfirmNext('remark')" :focus="focusField==='remark'" />
- </view>
- </view>
- <!-- 在非审核状态或授权到期状态显示提交按钮 -->
- <view v-if="!isReviewing || isExpired" class="fixed-buttom-btn" :class="{ 'can-submit': canSubmit || isExpired }" @click="onSubmit">
- <text class="btn-text">{{ isExpired ? '重新申请' : '申请授权' }}</text>
- </view>
- </scroll-view>
- </view>
- </template>
- <script>
- import { submitAuthorizationApply } from '@/utils/authorize.js';
- import AppConfirm from '@/components/app-confirm/app-confirm.vue'
- export default {
- components: { AppConfirm },
- data() {
- return {
- form: {
- hospital: '',
- department: '',
- name: '',
- phone: '',
- remark: ''
- },
- imei: '',
- // 当前聚焦的行,用于 scroll-into-view 将其滚入可视区域
- activeRowId: '',
- // 键盘占用的高度,H5 通过 visualViewport 获取
- kbGap: 0,
- // 是否处于待审核状态
- isReviewing: false,
- // 是否授权已到期
- isExpired: false,
- // 申请时间
- applyTime: '',
- // 当前聚焦字段,用于回车切换焦点
- focusField: ''
- }
- },
- onLoad(params) {
- this.imei = params && params.imei ? params.imei : '';
- // 检查是否授权到期
- if (params && params.expired === 'true') {
- this.isExpired = true;
- }
- // 若明确携带未授权状态,强制清空本地审核/到期缓存,避免误判
- if (params && params.status === 'unauthorized') {
- try {
- uni.removeStorageSync('authApplyInfo');
- uni.removeStorageSync('authExpiredInfo');
- } catch (e) {}
- }
- // 检查页面状态(审核中或授权到期)
- this.checkPageStatus();
- },
- mounted(){
- // 调试信息
- console.log('页面mounted - 当前状态:', {
- isReviewing: this.isReviewing,
- isExpired: this.isExpired,
- logoSrc: this.logoSrc,
- pageTitle: this.pageTitle
- });
-
- // 仅 H5:使用 visualViewport 计算键盘占用高度,作为底部填充,避免遮挡
- // #ifdef H5
- if (typeof window !== 'undefined' && window.visualViewport){
- const applyGap = () => {
- const gap = Math.max(0, window.innerHeight - window.visualViewport.height);
- this.kbGap = gap;
- document.documentElement.style.setProperty('--kb-gap', gap + 'px');
- };
- window.visualViewport.addEventListener('resize', applyGap);
- this.$once('hook:beforeDestroy', () => {
- window.visualViewport && window.visualViewport.removeEventListener('resize', applyGap);
- });
- applyGap();
- }
- // #endif
- },
- computed: {
- // 判断必填项是否都已填写(备注为选填)
- canSubmit() {
- return this.form.hospital &&
- this.form.department &&
- this.form.name &&
- this.form.phone;
- },
- // Logo源路径
- logoSrc() {
- console.log('计算logoSrc:', { isExpired: this.isExpired, isReviewing: this.isReviewing });
- if (this.isExpired) {
- return '/static/images/gray_logo.png';
- }
- return '/static/images/blue_logo.png';
- },
- // 页面标题
- pageTitle() {
- if (this.isExpired) {
- return '授权已到期';
- }
- if (this.isReviewing) {
- return '申请审核中...';
- }
- return '设备未授权';
- },
- // 页面描述
- pageDesc() {
- if (this.isExpired) {
- return '如需继续使用设备,请重新申请授权';
- }
- if (this.isReviewing) {
- return '您的申请已提交,我们将在3个工作日内联系您';
- }
- return '提交以下信息申请开通,我们将在3个工作日内联系您';
- }
- },
- methods: {
- // 检查页面状态(审核中或授权到期)
- checkPageStatus() {
- try {
- // 如果是授权到期状态
- if (this.isExpired) {
- // 授权到期时,从本地存储获取之前的申请信息用于显示
- const expiredInfo = uni.getStorageSync('authExpiredInfo');
- if (expiredInfo && expiredInfo.imei === this.imei) {
- this.form = {
- hospital: expiredInfo.hospital || '',
- department: expiredInfo.department || '',
- name: expiredInfo.name || '',
- phone: expiredInfo.phone || '',
- remark: expiredInfo.remark || ''
- };
- this.applyTime = expiredInfo.applyTime || '';
- }
- console.log('授权到期状态数据:', {
- isExpired: this.isExpired,
- form: this.form,
- applyTime: this.applyTime
- });
- return;
- }
- // 检查是否有待审核的申请信息
- const applyInfo = uni.getStorageSync('authApplyInfo');
- if (applyInfo && applyInfo.imei === this.imei) {
- // 如果存在申请信息且IMEI匹配,显示待审核状态
- this.isReviewing = true;
- this.form = {
- hospital: applyInfo.hospital || '',
- department: applyInfo.department || '',
- name: applyInfo.name || '',
- phone: applyInfo.phone || '',
- remark: applyInfo.remark || ''
- };
- this.applyTime = applyInfo.applyTime || '';
- console.log('待审核状态数据:', {
- isReviewing: this.isReviewing,
- form: this.form,
- applyTime: this.applyTime
- });
- return;
- }
- // 如果没有找到状态数据,显示默认的申请表单状态
- console.log('显示申请表单状态:', {
- isReviewing: this.isReviewing,
- isExpired: this.isExpired,
- imei: this.imei
- });
- } catch (e) {
- console.error('获取状态信息失败:', e);
- }
- },
- // 格式化申请时间
- formatApplyTime() {
- const now = new Date();
- const year = now.getFullYear();
- const month = String(now.getMonth() + 1).padStart(2, '0');
- const day = String(now.getDate()).padStart(2, '0');
- return `${year}年${month}月${day}日`;
- },
- onFocus(id){
- // 记录当前聚焦行,触发 scroll-into-view
- this.activeRowId = id;
- // H5 再次触发一次,等待键盘动画后保证可见
- // #ifdef H5
- setTimeout(() => { this.activeRowId = id; }, 250);
- // #endif
- },
- onBlur(){
- this.activeRowId = '';
- },
- // 回车切换到下一个表单项
- onConfirmNext(field){
- const order = ['hospital','department','name','phone','remark'];
- const idx = order.indexOf(field);
- const next = order[idx + 1];
- if (next) {
- this.focusField = next;
- // 触发展示到视口
- const idMap = {
- hospital: 'row-hospital',
- department: 'row-department',
- name: 'row-name',
- phone: 'row-phone',
- remark: 'row-remark'
- };
- this.onFocus(idMap[next]);
- } else {
- // 最后一项回车:提交
- this.focusField = '';
- this.onSubmit();
- }
- },
-
- // 图片加载成功
- onImageLoad() {
- console.log('Logo加载成功:', this.logoSrc);
- },
-
- // 图片加载失败
- onImageError(e) {
- console.error('Logo加载失败:', this.logoSrc, e);
- },
- async onSubmit() {
- // 如果是授权到期状态,切换到申请表单状态
- if (this.isExpired) {
- // 清除到期状态数据
- uni.removeStorageSync('authExpiredInfo');
- // 重置表单为初始空值(过期态下展示的 data 不能带入填写态)
- this.form = {
- hospital: '',
- department: '',
- name: '',
- phone: '',
- remark: ''
- };
- this.applyTime = '';
-
- // 切换到申请状态
- this.isExpired = false;
- this.isReviewing = false;
-
- uni.showToast({ title: '请重新填写申请信息', icon: 'none' });
- return;
- }
- // 普通申请状态的校验和提交
- if (!this.form.hospital || !this.form.department || !this.form.name || !this.form.phone) {
- uni.showToast({ title: '请完整填写必填信息', icon: 'none' });
- return;
- }
-
- const payload = { ...this.form, imei: this.imei };
- try {
- const ok = await submitAuthorizationApply(payload);
- if (ok) {
- // 保存申请信息到本地存储
- const applyInfo = {
- ...this.form,
- imei: this.imei,
- applyTime: this.formatApplyTime()
- };
- uni.setStorageSync('authApplyInfo', applyInfo);
-
- // 更新为待审核状态
- this.isReviewing = true;
- this.applyTime = applyInfo.applyTime;
-
- uni.showToast({ title: '提交成功,等待授权', icon: 'none' });
- // 不再跳转,直接在当前页面显示待审核状态
- }
- } catch(e) {
- // 接口层已统一弹窗提示错误,这里只阻止后续逻辑
- }
- }
- }
- }
- </script>
- <style lang="less" scoped>
- .apply-auth-page{
- background-color: #F5F7FA;
- /* 让整体随可视视口高度缩放,避免键盘遮挡 */
- .page-scroll{
- height: 100vh;
- height: 100svh;
- overflow-y: auto;
- -webkit-overflow-scrolling: touch;
- padding-bottom: calc(env(safe-area-inset-bottom) + var(--kb-gap, 0px));
- /* 使 scroll-into-view 目标行在底部仍留出空间 */
- scroll-padding-bottom: calc(env(safe-area-inset-bottom) + var(--kb-gap, 0px));
- }
- .top-banner{
- position: relative;
- margin-bottom: 0vh;
- .top-bg-img{width: 100%; display: block;}
- .head{
- position: absolute; left: 24rpx; top: 10vh; right: 24rpx;
- display:flex;align-items:flex-start;flex-direction:column;
- padding: 0 30rpx;
- .logo{
- width: 120rpx;
- height: 120rpx;
- margin-bottom: 60rpx;
- display: block;
- }
- .tit-wrap{display:flex;flex-direction:column;}
- .title{font-size: 45rpx;color:#292C33;margin-bottom: 20rpx;}
- .desc{font-size: 25rpx;color:#7A8499;line-height: 40rpx;}
- }
- }
- // 主表单卡片样式
- .form{
- background: #fff;
- border-radius: 18rpx;
- padding: 0 30rpx;
- margin:0 50rpx;
- box-shadow: 0 12rpx 36rpx rgba(0,0,0,0.04);
- .row{
- display:flex;align-items:center;min-height: 80rpx;
- &.no-border{border-bottom: none;}
- .label{width: 140rpx;color:#525866;font-size: 28rpx;}
- .ipt{flex:1;height: 100rpx;border: none;padding: 0 4rpx;font-size:28rpx;text-align: right;}
- .ph{color:#B8BFCC;font-size: 28rpx;}
- // 待审核状态的只读值样式
- .value{
- flex:1;
- text-align: right;
- font-size: 28rpx;
- color: #292C33;
- padding: 0 4rpx;
- }
- // 带图标的标签样式
- .label-with-icon{
- width: 180rpx;
- display: flex;
- align-items: center;
- flex-shrink: 0;
- .label-icon{
- width: 32rpx;
- height: 32rpx;
- margin-right: 16rpx;
- flex-shrink: 0;
- }
- .label{
- width: auto;
- flex: 1;
- white-space: nowrap;
- }
- }
- }
- // 待审核模式的特殊样式
- .review-mode{
- .row{
- padding: 30rpx 0;
- min-height: auto;
- }
- }
- }
- // 备注卡片
- .remark-card{
- margin:0 50rpx;
- margin-top: 1.5vh;
- background: #fff;
- border-radius: 18rpx;
- padding:5rpx 30rpx;
- box-shadow: 0 12rpx 36rpx rgba(0,0,0,0.04);
- .row{
- display:flex;
- align-items:center;
- min-height: 80rpx;
- // padding: 25rpx 0;
- }
- .label{width: 140rpx;color:#525866;font-size: 28rpx;}
- .ipt{flex:1;height: 100rpx;border: none;padding: 0 4rpx;font-size:28rpx;text-align: right;}
- .ph{color:#B8C0CC;font-size: 28rpx;}
- // 待审核状态的只读值样式
- .value{
- flex:1;
- text-align: right;
- font-size: 28rpx;
- color: #292C33;
- padding: 0 4rpx;
- }
- // 带图标的标签样式
- .label-with-icon{
- width: 180rpx;
- display: flex;
- align-items: center;
- flex-shrink: 0;
- .label-icon{
- width: 32rpx;
- height: 32rpx;
- margin-right: 16rpx;
- flex-shrink: 0;
- }
- .label{
- width: auto;
- flex: 1;
- white-space: nowrap;
- }
- }
- }
- // 申请授权按钮样式,跟随在内容后面 (使用!important覆盖全局样式)
- .fixed-buttom-btn{
- position: static !important;
- left: auto !important;
- bottom: auto !important;
- width: auto !important;
- margin: 3vh 50rpx 0vh 50rpx !important;
- height: 100rpx !important;
- border-radius: 60rpx !important;
- // 默认状态:灰色渐变背景
- background: linear-gradient(135deg, #A3B1CC 0%, #A3B1CC 100%) !important;
- box-shadow: 0 8rpx 24rpx rgba(139, 157, 195, 0.4) !important;
- display: flex !important;
- align-items: center !important;
- justify-content: center !important;
- transition: all 0.3s ease !important;
-
- // 可提交状态:蓝色背景
- &.can-submit {
- background: #3377FF !important;
- box-shadow: 0 8rpx 24rpx rgba(51, 119, 255, 0.4) !important;
- }
-
- &:active {
- transform: scale(0.98);
- }
-
- &:active:not(.can-submit) {
- box-shadow: 0 4rpx 12rpx rgba(139, 157, 195, 0.3);
- }
-
- &:active.can-submit {
- box-shadow: 0 4rpx 12rpx rgba(51, 119, 255, 0.3);
- }
-
- .btn-text{
- flex: none !important;
- font-size: 34rpx !important;
- color: #FFFFFF !important;
- font-weight: 600 !important;
- letter-spacing: 2rpx !important;
- }
- }
- }
- </style>
- ie a
|