2026-08-10-login-confirm-dialog.md 7.4 KB

登录确认弹窗(方案 F)Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 用自定义 F 样式确认弹窗替换登录页 uni.showModal,正文含《用户协议》《隐私政策》快捷链接。

Architecture: 新增通用 ConfirmDialog(遮罩 + 居中卡片 + 双按钮,支持默认插槽正文);登录页用插槽渲染协议链接并复用 openProtocol;样式对齐 mobile-ui/zkxw-mobile-login-confirm-dialog-demo.html 卡片 F。

Tech Stack: uni-app Vue(Options API)、SCSS、三墙 Token

Spec: docs/superpowers/specs/2026-08-10-login-confirm-dialog-design.md


File map

路径 职责
mobile-h5/components/ConfirmDialog.vue F 确认弹窗组件
mobile-h5/styles/components/confirm-dialog.scss 遮罩 / 卡片 / 链接样式
mobile-h5/pages/login/index.vue 接入弹窗,去掉 uni.showModal
mobile-h5/App.vue 引入 confirm-dialog.scss
docs/miniprogram-ui-spec-sanqiang.md 增加确认弹窗 Demo 指向
mobile-ui/zkxw-mobile-login-confirm-dialog-demo.html 已标注登录采用 F + 链接(已完成,本计划不再改)

Task 1: ConfirmDialog 样式

Files:

  • Create: mobile-h5/styles/components/confirm-dialog.scss
  • Modify: mobile-h5/App.vue

  • [x] Step 1: 写入 SCSS

.confirm-dialog {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 48rpx;
  box-sizing: border-box;
}

.confirm-dialog__mask {
  position: absolute;
  inset: 0;
  background: rgba(15, 30, 24, 0.32);
}

.confirm-dialog__panel {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 560rpx;
  background: #fff;
  border-radius: 28rpx;
  overflow: hidden;
  box-shadow: 0 20rpx 56rpx rgba(0, 0, 0, 0.14);
}

.confirm-dialog__body {
  padding: 44rpx 36rpx 32rpx;
  text-align: center;
}

.confirm-dialog__title {
  margin: 0 0 16rpx;
  font-size: 34rpx;
  font-weight: 650;
  color: var(--text-primary, #1f2a26);
  line-height: 1.35;
}

.confirm-dialog__content {
  margin: 0;
  font-size: 26rpx;
  color: #555;
  line-height: 1.5;
}

.confirm-dialog__link {
  color: var(--brand-green, #0a9f6d);
  font-weight: 500;
}

.confirm-dialog__actions {
  display: flex;
  border-top: 1px solid #e8e8e8;
}

.confirm-dialog__btn {
  flex: 1;
  height: 96rpx;
  line-height: 96rpx;
  text-align: center;
  font-size: 32rpx;
  background: transparent;
}

.confirm-dialog__btn--cancel {
  color: #666;
  border-right: 1px solid #e8e8e8;
}

.confirm-dialog__btn--confirm {
  color: var(--brand-green, #0a9f6d);
  font-weight: 600;
}
  • Step 2: App.vue 引入

在 App.vue 的 style 中增加:

@import './styles/components/confirm-dialog.scss';

(放在 login.scss 附近即可)

  • Step 3: Commit(若用户要求提交时再执行)
git add mobile-h5/styles/components/confirm-dialog.scss mobile-h5/App.vue
git commit -m "$(cat <<'EOF'
style(mobile-h5): add confirm dialog F styles

EOF
)"

Task 2: ConfirmDialog 组件

Files:

  • Create: mobile-h5/components/ConfirmDialog.vue

  • [x] Step 1: 创建组件

<template>
  <view
    v-if="show"
    class="confirm-dialog"
    @touchmove.stop.prevent
  >
    <view class="confirm-dialog__mask" @click="onCancel" />
    <view class="confirm-dialog__panel">
      <view class="confirm-dialog__body">
        <view class="confirm-dialog__title">{{ title }}</view>
        <view class="confirm-dialog__content">
          <slot>{{ content }}</slot>
        </view>
      </view>
      <view class="confirm-dialog__actions">
        <view
          class="confirm-dialog__btn confirm-dialog__btn--cancel"
          @click="onCancel"
        >
          {{ cancelText }}
        </view>
        <view
          class="confirm-dialog__btn confirm-dialog__btn--confirm"
          @click="onConfirm"
        >
          {{ confirmText }}
        </view>
      </view>
    </view>
  </view>
</template>

<script>
  export default {
    name: 'ConfirmDialog',
    props: {
      show: { type: Boolean, default: false },
      title: { type: String, default: '请先同意协议' },
      content: { type: String, default: '' },
      cancelText: { type: String, default: '取消' },
      confirmText: { type: String, default: '同意并登录' }
    },
    methods: {
      onCancel() {
        this.$emit('update:show', false)
        this.$emit('cancel')
      },
      onConfirm() {
        this.$emit('update:show', false)
        this.$emit('confirm')
      }
    }
  }
</script>
  • Step 2: 自检

确认:无插槽时渲染 content;有插槽时插槽优先;遮罩点击触发 cancel。


Task 3: 登录页接入

Files:

  • Modify: mobile-h5/pages/login/index.vue

  • [x] Step 1: 模板增加 ConfirmDialog

在根 </view> 前插入:

    <ConfirmDialog
      :show="agreeDialogVisible"
      title="请先同意协议"
      cancel-text="取消"
      confirm-text="同意并登录"
      @update:show="agreeDialogVisible = $event"
      @confirm="onAgreeConfirm"
      @cancel="onAgreeCancel"
    >
      <text>登录前需阅读并同意</text>
      <text class="confirm-dialog__link" @click.stop="openProtocol('user')">
        《用户协议》
      </text>
      <text>和</text>
      <text class="confirm-dialog__link" @click.stop="openProtocol('privacy')">
        《隐私政策》
      </text>
      <text>。是否同意并继续登录?</text>
    </ConfirmDialog>
  • Step 2: script 改造
  1. import ConfirmDialog from '../../components/ConfirmDialog.vue'
  2. components: { ConfirmDialog }
  3. data 增加:agreeDialogVisible: false,以及 _agreeResolver: null(或仅用实例字段,不放 data)
  4. 替换 ensureAgree / 新增确认回调:
ensureAgree() {
  if (this.agreed) return Promise.resolve(true)
  this.agreeDialogVisible = true
  return new Promise((resolve) => {
    this._agreeResolver = resolve
  })
},
onAgreeConfirm() {
  this.agreed = true
  this.agreeDialogVisible = false
  if (this._agreeResolver) {
    this._agreeResolver(true)
    this._agreeResolver = null
  }
},
onAgreeCancel() {
  this.agreeDialogVisible = false
  if (this._agreeResolver) {
    this._agreeResolver(false)
    this._agreeResolver = null
  }
},
  1. 删除 uni.showModal 调用。
  • Step 3: 手工验收
  1. 未勾选点登录 → F 弹窗出现
  2. 点《用户协议》→ 协议页;返回后弹窗仍在
  3. 同意并登录 → 勾选为开并登录
  4. 取消 / 遮罩 → 不登录

Task 4: 规范短注

Files:

  • Modify: docs/miniprogram-ui-spec-sanqiang.md(登录 Demo 列表附近)

  • [x] Step 1: 增加两行指向

在现有登录 Demo / 设计指向后追加:

- 登录确认弹窗 Demo:`mobile-ui/zkxw-mobile-login-confirm-dialog-demo.html`(登录采用方案 F;A–F 保留)
- 登录确认弹窗设计:`docs/superpowers/specs/2026-08-10-login-confirm-dialog-design.md`

Spec coverage checklist

Spec 要求 Task
F 视觉(遮罩/卡片/双按钮/确认绿) 1, 2
替换 showModal 3
协议快捷链接 + 返回后弹窗仍在 3
Demo A–F 保留、登录标 F 已完成
规范指向 4