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
| 路径 | 职责 |
|---|---|
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 + 链接(已完成,本计划不再改) |
Files:
mobile-h5/styles/components/confirm-dialog.scssModify: 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;
}
在 App.vue 的 style 中增加:
@import './styles/components/confirm-dialog.scss';
(放在 login.scss 附近即可)
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
)"
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>
确认:无插槽时渲染 content;有插槽时插槽优先;遮罩点击触发 cancel。
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>
import ConfirmDialog from '../../components/ConfirmDialog.vue'components: { ConfirmDialog }data 增加:agreeDialogVisible: false,以及 _agreeResolver: null(或仅用实例字段,不放 data)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
}
},
uni.showModal 调用。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 要求 | Task |
|---|---|
| F 视觉(遮罩/卡片/双按钮/确认绿) | 1, 2 |
| 替换 showModal | 3 |
| 协议快捷链接 + 返回后弹窗仍在 | 3 |
| Demo A–F 保留、登录标 F | 已完成 |
| 规范指向 | 4 |