|
|
@@ -0,0 +1,302 @@
|
|
|
+<template>
|
|
|
+ <view class="notify-page">
|
|
|
+ <view class="notify-body">
|
|
|
+ <!-- 步骤 1:关注服务号 -->
|
|
|
+ <view class="step-card" :class="{ 'is-done': step1Done }">
|
|
|
+ <view class="step-hd">
|
|
|
+ <view class="step-num">1</view>
|
|
|
+ <view class="step-main">
|
|
|
+ <view class="step-title">关注服务号</view>
|
|
|
+ <view class="step-desc">
|
|
|
+ 关注后才能接收微信模板消息。可跳转服务号主页,或长按识别二维码。
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <text class="step-badge" :class="{ 'is-done': step1Done }">
|
|
|
+ {{ step1Done ? '已完成' : '未完成' }}
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ <view class="step-actions">
|
|
|
+ <button class="btn btn-primary" @click="onFollow">
|
|
|
+ {{ step1Done ? '重新打开关注页' : '去关注' }}
|
|
|
+ </button>
|
|
|
+ <view v-if="showQr && !step1Done" class="qr-box">
|
|
|
+ <image
|
|
|
+ class="qr-img"
|
|
|
+ :src="mpQrcodeUrl"
|
|
|
+ mode="aspectFit"
|
|
|
+ show-menu-by-longpress
|
|
|
+ />
|
|
|
+ <text class="qr-tip">长按识别关注</text>
|
|
|
+ <button class="btn btn-ghost" @click="onConfirmFollowed">我已关注</button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 步骤 2:绑定账号 -->
|
|
|
+ <view class="step-card" :class="{ 'is-done': step2Done }">
|
|
|
+ <view class="step-hd">
|
|
|
+ <view class="step-num">2</view>
|
|
|
+ <view class="step-main">
|
|
|
+ <view class="step-title">绑定当前账号</view>
|
|
|
+ <view class="step-desc">
|
|
|
+ 将服务号身份与系统账号关联,审批待办 / 抄送才能推送到你。
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ <text class="step-badge" :class="{ 'is-done': step2Done }">
|
|
|
+ {{ step2Done ? '已完成' : '未完成' }}
|
|
|
+ </text>
|
|
|
+ </view>
|
|
|
+ <view class="step-actions">
|
|
|
+ <button
|
|
|
+ class="btn btn-primary"
|
|
|
+ :disabled="!step1Done || step2Done"
|
|
|
+ @click="onBind"
|
|
|
+ >
|
|
|
+ {{
|
|
|
+ step2Done
|
|
|
+ ? '已绑定'
|
|
|
+ : step1Done
|
|
|
+ ? '去绑定'
|
|
|
+ : '请先完成步骤 1'
|
|
|
+ }}
|
|
|
+ </button>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import {
|
|
|
+ fetchMpBindStatus,
|
|
|
+ getUser,
|
|
|
+ forceRelogin,
|
|
|
+ getToken
|
|
|
+} from '../../../utils/auth.js'
|
|
|
+import {
|
|
|
+ isFollowConfirmed,
|
|
|
+ setFollowConfirmed,
|
|
|
+ resolveStepDone
|
|
|
+} from '../../../utils/mp-follow-confirm.js'
|
|
|
+import { MP_GH_USERNAME, MP_QRCODE_URL } from '../../../utils/config.js'
|
|
|
+
|
|
|
+function currentUserId() {
|
|
|
+ const u = getUser() || {}
|
|
|
+ return u.id || u.userId || u.username || ''
|
|
|
+}
|
|
|
+
|
|
|
+export default {
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ bound: false,
|
|
|
+ followConfirmed: false,
|
|
|
+ showQr: false,
|
|
|
+ mpQrcodeUrl: MP_QRCODE_URL,
|
|
|
+ step1Done: false,
|
|
|
+ step2Done: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onShow() {
|
|
|
+ if (!getToken()) {
|
|
|
+ forceRelogin('请先登录')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.followConfirmed = isFollowConfirmed(currentUserId())
|
|
|
+ this.refreshBind()
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ applySteps() {
|
|
|
+ const r = resolveStepDone({
|
|
|
+ bound: this.bound,
|
|
|
+ followConfirmed: this.followConfirmed
|
|
|
+ })
|
|
|
+ this.step1Done = r.step1Done
|
|
|
+ this.step2Done = r.step2Done
|
|
|
+ },
|
|
|
+ async refreshBind() {
|
|
|
+ try {
|
|
|
+ const res = await fetchMpBindStatus()
|
|
|
+ this.bound = !!(res && res.bound)
|
|
|
+ } catch (_) {
|
|
|
+ this.bound = false
|
|
|
+ }
|
|
|
+ this.applySteps()
|
|
|
+ },
|
|
|
+ onFollow() {
|
|
|
+ const username = (MP_GH_USERNAME || '').trim()
|
|
|
+ const openProfile =
|
|
|
+ typeof wx !== 'undefined' && typeof wx.openOfficialAccountProfile === 'function'
|
|
|
+ if (openProfile && username) {
|
|
|
+ wx.openOfficialAccountProfile({
|
|
|
+ username,
|
|
|
+ fail: () => {
|
|
|
+ this.showQr = true
|
|
|
+ }
|
|
|
+ })
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.showQr = true
|
|
|
+ },
|
|
|
+ onConfirmFollowed() {
|
|
|
+ setFollowConfirmed(currentUserId(), true)
|
|
|
+ this.followConfirmed = true
|
|
|
+ this.showQr = false
|
|
|
+ this.applySteps()
|
|
|
+ uni.showToast({ title: '已标记关注', icon: 'none' })
|
|
|
+ },
|
|
|
+ onBind() {
|
|
|
+ if (!this.step1Done || this.step2Done) return
|
|
|
+ uni.navigateTo({ url: '/pages/oa/mp-bind/index' })
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.notify-page {
|
|
|
+ min-height: 100vh;
|
|
|
+ background: #f5f8f7;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+.notify-body {
|
|
|
+ padding: 28rpx 24rpx 56rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.step-card {
|
|
|
+ background: #fff;
|
|
|
+ border: 1px solid #dcebe4;
|
|
|
+ border-radius: 28rpx;
|
|
|
+ padding: 28rpx;
|
|
|
+ margin-bottom: 20rpx;
|
|
|
+
|
|
|
+ &.is-done {
|
|
|
+ border-color: #b7ebcf;
|
|
|
+ background: linear-gradient(180deg, #f6fffb 0%, #fff 60%);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.step-hd {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ gap: 20rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.step-num {
|
|
|
+ width: 56rpx;
|
|
|
+ height: 56rpx;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: #0a9f6d;
|
|
|
+ color: #fff;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: 700;
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.step-card.is-done .step-num {
|
|
|
+ background: #189b65;
|
|
|
+}
|
|
|
+
|
|
|
+.step-main {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.step-title {
|
|
|
+ font-size: 30rpx;
|
|
|
+ font-weight: 700;
|
|
|
+ line-height: 1.35;
|
|
|
+ color: #1f2a26;
|
|
|
+}
|
|
|
+
|
|
|
+.step-desc {
|
|
|
+ margin-top: 8rpx;
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #6b7b74;
|
|
|
+ line-height: 1.5;
|
|
|
+}
|
|
|
+
|
|
|
+.step-badge {
|
|
|
+ margin-left: auto;
|
|
|
+ font-size: 22rpx;
|
|
|
+ padding: 4rpx 16rpx;
|
|
|
+ border-radius: 999rpx;
|
|
|
+ background: #eef2f0;
|
|
|
+ color: #6b7b74;
|
|
|
+ flex-shrink: 0;
|
|
|
+ line-height: 1.4;
|
|
|
+
|
|
|
+ &.is-done {
|
|
|
+ background: #e9f9f2;
|
|
|
+ color: #087f57;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.step-actions {
|
|
|
+ margin-top: 24rpx;
|
|
|
+ padding-left: 76rpx;
|
|
|
+}
|
|
|
+
|
|
|
+.btn {
|
|
|
+ appearance: none;
|
|
|
+ border: 0;
|
|
|
+ border-radius: 20rpx;
|
|
|
+ padding: 20rpx 28rpx;
|
|
|
+ font-size: 28rpx;
|
|
|
+ font-weight: 600;
|
|
|
+ min-height: 80rpx;
|
|
|
+ line-height: 1.3;
|
|
|
+ box-sizing: border-box;
|
|
|
+
|
|
|
+ &::after {
|
|
|
+ border: none;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.btn-primary {
|
|
|
+ background: #0a9f6d;
|
|
|
+ color: #fff;
|
|
|
+ width: 100%;
|
|
|
+
|
|
|
+ &[disabled] {
|
|
|
+ background: #a7d7c4;
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.btn-ghost {
|
|
|
+ margin-top: 20rpx;
|
|
|
+ background: #fff;
|
|
|
+ color: #087f57;
|
|
|
+ border: 1px solid #dcebe4;
|
|
|
+ width: 100%;
|
|
|
+}
|
|
|
+
|
|
|
+.qr-box {
|
|
|
+ margin-top: 20rpx;
|
|
|
+ padding: 24rpx;
|
|
|
+ border-radius: 24rpx;
|
|
|
+ border: 1px dashed #a7f3d0;
|
|
|
+ background: #f8fffb;
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+
|
|
|
+.qr-img {
|
|
|
+ display: block;
|
|
|
+ width: 280rpx;
|
|
|
+ height: 280rpx;
|
|
|
+ margin: 0 auto;
|
|
|
+ border-radius: 16rpx;
|
|
|
+ background: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.qr-tip {
|
|
|
+ display: block;
|
|
|
+ margin-top: 16rpx;
|
|
|
+ font-size: 24rpx;
|
|
|
+ color: #6b7b74;
|
|
|
+}
|
|
|
+</style>
|