Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
810eba0a63 |
@@ -281,21 +281,71 @@ class Distribution extends BaseController
|
||||
$now = time();
|
||||
foreach ($rows as $r) {
|
||||
$exp = isset($r['expiresAt']) ? (int) $r['expiresAt'] : 0;
|
||||
if ($exp <= 0 || $exp > $now) {
|
||||
$code = trim((string) ($r['code'] ?? ''));
|
||||
if ($code !== '') {
|
||||
return success([
|
||||
'code' => strtoupper($code),
|
||||
'createdNew' => false,
|
||||
]);
|
||||
if ($exp > 0 && $exp <= $now) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$numericCol = trim((string) ($r['code_numeric'] ?? ''));
|
||||
$codeCol = trim((string) ($r['code'] ?? ''));
|
||||
if ($numericCol === '' && $codeCol !== '' && preg_match('/^[0-9]+$/', $codeCol)) {
|
||||
$numericCol = $codeCol;
|
||||
}
|
||||
|
||||
$replenishedNumeric = false;
|
||||
// 仅有老版或未迁移字段时:强制补发数字码(与 code_legacy 并存)
|
||||
if ($numericCol === '') {
|
||||
for ($try = 0; $try < 8; $try++) {
|
||||
try {
|
||||
$newNumeric = $this->generateUniqueNumericInviteCode();
|
||||
$rowId = (int) ($r['id'] ?? 0);
|
||||
if ($rowId <= 0) {
|
||||
break;
|
||||
}
|
||||
Db::name('invite_codes')->where('id', $rowId)->update([
|
||||
'code_numeric' => $newNumeric,
|
||||
'code' => $newNumeric,
|
||||
'updatedAt' => $now,
|
||||
]);
|
||||
$r['code_numeric'] = $newNumeric;
|
||||
$r['code'] = $newNumeric;
|
||||
$replenishedNumeric = true;
|
||||
break;
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('myInviteCode replenish numeric try ' . $try . ': ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$payload = $this->buildInviteCodeApiPayload($r);
|
||||
if (($payload['code'] ?? '') === '') {
|
||||
continue;
|
||||
}
|
||||
$numOut = $payload['numericCode'] ?? null;
|
||||
if ($numOut === null || $numOut === '') {
|
||||
Log::warning('myInviteCode numeric still missing after replenish', [
|
||||
'inviterId' => $inviterId,
|
||||
'rowId' => (int) ($r['id'] ?? 0),
|
||||
]);
|
||||
|
||||
return error('数字邀请码生成失败,请稍后重试', 503);
|
||||
}
|
||||
|
||||
$out = array_merge($payload, [
|
||||
'createdNew' => false,
|
||||
]);
|
||||
if ($replenishedNumeric) {
|
||||
$out['replenishedNumeric'] = true;
|
||||
}
|
||||
|
||||
return success($out);
|
||||
}
|
||||
|
||||
try {
|
||||
$newCode = $this->generateUniqueInviteCode();
|
||||
$pair = $this->generateUniqueInvitePair();
|
||||
Db::name('invite_codes')->insert([
|
||||
'code' => $newCode,
|
||||
'code' => $pair['numeric'],
|
||||
'code_numeric' => $pair['numeric'],
|
||||
'code_legacy' => $pair['legacy'],
|
||||
'inviterId' => $inviterId,
|
||||
'enterpriseId' => null,
|
||||
'status' => 'active',
|
||||
@@ -308,18 +358,50 @@ class Distribution extends BaseController
|
||||
Log::warning('myInviteCode insert: ' . $e->getMessage());
|
||||
|
||||
return success([
|
||||
'code' => null,
|
||||
'createdNew' => false,
|
||||
'hint' => '暂时无法生成邀请码,请稍后重试或联系管理员',
|
||||
'code' => null,
|
||||
'numericCode' => null,
|
||||
'legacyCode' => null,
|
||||
'createdNew' => false,
|
||||
'hint' => '暂时无法生成邀请码,请稍后重试或联系管理员',
|
||||
]);
|
||||
}
|
||||
|
||||
return success([
|
||||
'code' => $newCode,
|
||||
'createdNew' => true,
|
||||
'code' => $pair['numeric'],
|
||||
'numericCode' => $pair['numeric'],
|
||||
'legacyCode' => $pair['legacy'],
|
||||
'createdNew' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $row invite_codes 一行
|
||||
* @return array{code:string,numericCode:?string,legacyCode:?string}
|
||||
*/
|
||||
private function buildInviteCodeApiPayload(array $row): array
|
||||
{
|
||||
$numeric = trim((string) ($row['code_numeric'] ?? ''));
|
||||
$legacy = trim((string) ($row['code_legacy'] ?? ''));
|
||||
$codeCol = trim((string) ($row['code'] ?? ''));
|
||||
|
||||
if ($numeric === '' && $codeCol !== '' && preg_match('/^[0-9]+$/', $codeCol)) {
|
||||
$numeric = $codeCol;
|
||||
}
|
||||
if ($legacy === '' && $codeCol !== '' && !preg_match('/^[0-9]+$/', $codeCol)) {
|
||||
$legacy = strtoupper($codeCol);
|
||||
}
|
||||
|
||||
$numericOut = $numeric !== '' ? $numeric : null;
|
||||
$legacyOut = $legacy !== '' ? strtoupper($legacy) : null;
|
||||
$display = $numericOut ?? $legacyOut ?? '';
|
||||
|
||||
return [
|
||||
'code' => $display,
|
||||
'numericCode' => $numericOut,
|
||||
'legacyCode' => $legacyOut,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 过期待收款提现:status=2 超过24小时未确认收款的,自动退回余额并标记为已过期
|
||||
*/
|
||||
@@ -1658,32 +1740,101 @@ class Distribution extends BaseController
|
||||
}
|
||||
|
||||
/**
|
||||
* 活动邀请码 → inviterId(需表 invite_codes,见 database/add_invite_codes.sql)
|
||||
*
|
||||
* @param string $raw
|
||||
* @param int|null $requestEnterpriseId 请求里已带的 eid,用于与码上企业校验
|
||||
* @return array{inviterId:int, enterpriseId:int|null}|null
|
||||
* 判断邀请码字符串是否已被占用(数字码 / 老版码 / 兼容字段 code 任一命中即占用)
|
||||
*/
|
||||
private function inviteCodeTokenTaken(string $token): bool
|
||||
{
|
||||
$token = trim($token);
|
||||
if ($token === '') {
|
||||
return true;
|
||||
}
|
||||
$norm = strtoupper(preg_replace('/[^A-Za-z0-9]/', '', $token));
|
||||
if ($norm === '') {
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
$row = Db::name('invite_codes')
|
||||
->where(function ($query) use ($norm) {
|
||||
$query->where('code_numeric', $norm)
|
||||
->whereOr('code_legacy', $norm)
|
||||
->whereOr('code', $norm);
|
||||
})
|
||||
->find();
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('inviteCodeTokenTaken: ' . $e->getMessage());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return (bool) $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成不与 invite_codes.code 冲突的随机码(易辨认字符集)
|
||||
* 数字邀请码:6 位 100000–999999,7 位 1000000–9999999,以此类推;用尽则加长位数(上限 12 位)
|
||||
*/
|
||||
private function generateUniqueInviteCode(): string
|
||||
private function generateUniqueNumericInviteCode(): string
|
||||
{
|
||||
$maxLen = 12;
|
||||
for ($len = 6; $len <= $maxLen; $len++) {
|
||||
$min = (int) pow(10, $len - 1);
|
||||
$max = (int) pow(10, $len) - 1;
|
||||
$attemptsPerLen = $len <= 7 ? 96 : 48;
|
||||
for ($attempt = 0; $attempt < $attemptsPerLen; $attempt++) {
|
||||
$code = (string) random_int($min, $max);
|
||||
if (!$this->inviteCodeTokenTaken($code)) {
|
||||
return $code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new \RuntimeException('invite numeric code exhausted');
|
||||
}
|
||||
|
||||
/**
|
||||
* 老版邀请码:8 位易辨认字母数字(与原逻辑一致),与数字码分列存储、均可绑定
|
||||
*
|
||||
* @param string $excludeNumeric 同一用户本次已生成的数字码,避免与老版随机串完全相同
|
||||
*/
|
||||
private function generateUniqueLegacyInviteCode(string $excludeNumeric): string
|
||||
{
|
||||
$chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
|
||||
$max = strlen($chars) - 1;
|
||||
for ($attempt = 0; $attempt < 24; $attempt++) {
|
||||
for ($round = 0; $round < 64; $round++) {
|
||||
$code = '';
|
||||
for ($i = 0; $i < 8; $i++) {
|
||||
$code .= $chars[random_int(0, $max)];
|
||||
}
|
||||
$exists = Db::name('invite_codes')->where('code', $code)->find();
|
||||
if (!$exists) {
|
||||
return $code;
|
||||
$norm = strtoupper($code);
|
||||
if ($excludeNumeric !== '' && $norm === $excludeNumeric) {
|
||||
continue;
|
||||
}
|
||||
if (!$this->inviteCodeTokenTaken($norm)) {
|
||||
return $norm;
|
||||
}
|
||||
}
|
||||
throw new \RuntimeException('invite code collision');
|
||||
|
||||
throw new \RuntimeException('invite legacy code collision');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{numeric:string,legacy:string}
|
||||
*/
|
||||
private function generateUniqueInvitePair(): array
|
||||
{
|
||||
$numeric = $this->generateUniqueNumericInviteCode();
|
||||
|
||||
return [
|
||||
'numeric' => $numeric,
|
||||
'legacy' => $this->generateUniqueLegacyInviteCode($numeric),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 活动邀请码 → inviterId(需表 invite_codes,见 database/add_invite_codes.sql)
|
||||
* 支持填写 code_numeric、code_legacy 或兼容字段 code
|
||||
*
|
||||
* @return array{inviterId:int, enterpriseId:int|null}|null
|
||||
*/
|
||||
private function resolveInviterFromInviteCode(string $raw, ?int $requestEnterpriseId): ?array
|
||||
{
|
||||
$norm = strtoupper(preg_replace('/[^A-Za-z0-9]/', '', $raw));
|
||||
@@ -1692,8 +1843,12 @@ class Distribution extends BaseController
|
||||
}
|
||||
try {
|
||||
$row = Db::name('invite_codes')
|
||||
->where('code', $norm)
|
||||
->where('status', 'active')
|
||||
->where(function ($query) use ($norm) {
|
||||
$query->where('code_numeric', $norm)
|
||||
->whereOr('code_legacy', $norm)
|
||||
->whereOr('code', $norm);
|
||||
})
|
||||
->find();
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('invite_codes lookup failed: ' . $e->getMessage());
|
||||
|
||||
@@ -3,7 +3,9 @@
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `mbti_invite_codes` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT,
|
||||
`code` varchar(64) NOT NULL COMMENT '邀请码(仅存大写字母数字)',
|
||||
`code` varchar(64) NULL DEFAULT NULL COMMENT '兼容旧字段,可与 code_numeric 同步',
|
||||
`code_numeric` varchar(20) NULL DEFAULT NULL COMMENT '数字邀请码,如 6 位 100000-999999',
|
||||
`code_legacy` varchar(64) NULL DEFAULT NULL COMMENT '老版字母数字邀请码,与数字码同一 inviter 可并存',
|
||||
`inviterId` int unsigned NOT NULL COMMENT '推广员 wechat_users.id',
|
||||
`enterpriseId` int unsigned NULL DEFAULT NULL COMMENT '企业上下文,与个人版并行时可空',
|
||||
`status` varchar(20) NOT NULL DEFAULT 'active' COMMENT 'active|disabled',
|
||||
@@ -12,6 +14,7 @@ CREATE TABLE IF NOT EXISTS `mbti_invite_codes` (
|
||||
`createdAt` int unsigned NULL DEFAULT NULL,
|
||||
`updatedAt` int unsigned NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_code` (`code`),
|
||||
UNIQUE KEY `uk_code_numeric` (`code_numeric`),
|
||||
UNIQUE KEY `uk_code_legacy` (`code_legacy`),
|
||||
KEY `idx_inviterId` (`inviterId`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='小程序填写邀请码解析用';
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
-- 邀请码拆分为:数字码 code_numeric、老版码 code_legacy;两列均可用于填写解析
|
||||
-- 表名前缀与 api/config/database.php 中 prefix 对齐(默认 mbti_)
|
||||
-- 执行前请确认表名,如为 invite_codes 则把 mbti_invite_codes 替换为 {prefix}invite_codes
|
||||
|
||||
-- 1) 新列
|
||||
ALTER TABLE `mbti_invite_codes`
|
||||
ADD COLUMN `code_numeric` varchar(20) NULL DEFAULT NULL COMMENT '数字邀请码(如 100000-999999)' AFTER `code`,
|
||||
ADD COLUMN `code_legacy` varchar(64) NULL DEFAULT NULL COMMENT '老版字母数字邀请码' AFTER `code_numeric`;
|
||||
|
||||
-- 2) 回填:原 code 视作老版展示码(用户填写的多为旧格式)
|
||||
UPDATE `mbti_invite_codes`
|
||||
SET `code_legacy` = UPPER(TRIM(`code`))
|
||||
WHERE (`code_legacy` IS NULL OR `code_legacy` = '')
|
||||
AND `code` IS NOT NULL AND TRIM(`code`) <> '';
|
||||
|
||||
-- 3) 若历史已是纯数字仅存于 code,写入 code_numeric
|
||||
UPDATE `mbti_invite_codes`
|
||||
SET `code_numeric` = TRIM(`code`)
|
||||
WHERE TRIM(`code`) REGEXP '^[0-9]+$'
|
||||
AND (`code_numeric` IS NULL OR `code_numeric` = '');
|
||||
|
||||
-- 4) 去掉 code 唯一约束,改为数字码/老版码分别唯一(允许多列 NULL)
|
||||
ALTER TABLE `mbti_invite_codes` DROP INDEX `uk_code`;
|
||||
|
||||
ALTER TABLE `mbti_invite_codes`
|
||||
ADD UNIQUE KEY `uk_code_numeric` (`code_numeric`),
|
||||
ADD UNIQUE KEY `uk_code_legacy` (`code_legacy`);
|
||||
|
||||
-- 5) code 改为可空,仅作兼容旧读取
|
||||
ALTER TABLE `mbti_invite_codes`
|
||||
MODIFY `code` varchar(64) NULL DEFAULT NULL COMMENT '兼容旧字段,与新码同步时可等于数字码';
|
||||
@@ -6,7 +6,7 @@
|
||||
class="icd-input"
|
||||
type="text"
|
||||
maxlength="{{maxLen}}"
|
||||
placeholder="字母或数字"
|
||||
placeholder="100000-999999 数字码,或老版字母数字码"
|
||||
placeholder-class="icd-ph"
|
||||
value="{{code}}"
|
||||
bindinput="onInput"
|
||||
|
||||
@@ -13,7 +13,9 @@ Page({
|
||||
maintenanceMode: false,
|
||||
reviewMode: false,
|
||||
permFace: true,
|
||||
showVersionPicker: false
|
||||
showVersionPicker: false,
|
||||
versionPickerCurrent: 'enterprise',
|
||||
versionPickerCurrentLabel: '企业版'
|
||||
},
|
||||
_navigateByVersion(version) {
|
||||
try {
|
||||
@@ -32,7 +34,11 @@ Page({
|
||||
},
|
||||
|
||||
openVersionPicker() {
|
||||
this.setData({ showVersionPicker: true })
|
||||
this.setData({
|
||||
showVersionPicker: true,
|
||||
versionPickerCurrent: 'enterprise',
|
||||
versionPickerCurrentLabel: '企业版'
|
||||
})
|
||||
},
|
||||
|
||||
closeVersionPicker() {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<view class="navbar-content">
|
||||
<view class="switch-personal-btn" bindtap="switchToPersonal">
|
||||
<text class="personal-icon">👤</text>
|
||||
<text class="personal-text">个人版</text>
|
||||
<text class="personal-text">企业版</text>
|
||||
</view>
|
||||
<view class="navbar-title">{{siteTitle || '神仙团队性格测试'}}</view>
|
||||
<view class="navbar-placeholder"></view>
|
||||
@@ -82,14 +82,12 @@
|
||||
<view class="version-picker-close" bindtap="closeVersionPicker">×</view>
|
||||
</view>
|
||||
<view class="version-picker-title">请选择使用版本</view>
|
||||
<view class="version-picker-current">当前入口:<text class="version-picker-current-em">{{versionPickerCurrentLabel}}</text></view>
|
||||
<view class="version-picker-desc">当前企业支持三种版本,选择后将进入对应流程</view>
|
||||
<view class="version-picker-actions">
|
||||
<button class="version-btn version-btn-personal" data-version="personal" bindtap="selectVersion">个人版</button>
|
||||
<button class="version-btn version-btn-enterprise" data-version="enterprise" bindtap="selectVersion">企业版</button>
|
||||
<button class="version-btn version-btn-gaokao" data-version="gaokao" bindtap="selectVersion">高考版</button>
|
||||
</view>
|
||||
<view class="version-picker-foot">
|
||||
<button class="version-cancel-btn" bindtap="closeVersionPicker">取消</button>
|
||||
<button class="version-btn version-btn-personal {{versionPickerCurrent === 'personal' ? 'version-btn-is-current' : ''}}" data-version="personal" bindtap="selectVersion">个人版</button>
|
||||
<button class="version-btn version-btn-enterprise {{versionPickerCurrent === 'enterprise' ? 'version-btn-is-current' : ''}}" data-version="enterprise" bindtap="selectVersion">企业版</button>
|
||||
<button class="version-btn version-btn-gaokao {{versionPickerCurrent === 'gaokao' ? 'version-btn-is-current' : ''}}" data-version="gaokao" bindtap="selectVersion">高考版</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -98,17 +98,19 @@
|
||||
|
||||
.top-image-section {
|
||||
width: 100%;
|
||||
padding: 15rpx 40rpx 20rpx;
|
||||
padding: 8rpx 40rpx 10rpx;
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-top: 0;
|
||||
margin-top: -20rpx;
|
||||
}
|
||||
|
||||
.image-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
transform: translateY(-26rpx);
|
||||
margin-bottom: -26rpx;
|
||||
}
|
||||
|
||||
.image-wrapper {
|
||||
@@ -163,7 +165,7 @@
|
||||
}
|
||||
|
||||
.process-section {
|
||||
padding: 15rpx 40rpx 20rpx;
|
||||
padding: 8rpx 40rpx 20rpx;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
@@ -249,7 +251,7 @@
|
||||
.version-picker-mask {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(10, 15, 30, 0.52);
|
||||
background: rgba(10, 15, 30, 0.44);
|
||||
z-index: 20000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -260,11 +262,12 @@
|
||||
|
||||
.version-picker-dialog {
|
||||
width: 100%;
|
||||
max-width: 640rpx;
|
||||
background: #fff;
|
||||
border-radius: 30rpx;
|
||||
padding: 26rpx 30rpx 24rpx;
|
||||
box-shadow: 0 24rpx 70rpx rgba(16, 24, 40, 0.28);
|
||||
max-width: 620rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 36rpx;
|
||||
padding: 30rpx 30rpx 30rpx;
|
||||
border: 1rpx solid rgba(99, 102, 241, 0.12);
|
||||
box-shadow: 0 30rpx 80rpx rgba(15, 23, 42, 0.22);
|
||||
}
|
||||
|
||||
.version-picker-head {
|
||||
@@ -274,59 +277,96 @@
|
||||
}
|
||||
|
||||
.version-picker-badge {
|
||||
padding: 8rpx 18rpx;
|
||||
padding: 8rpx 20rpx;
|
||||
border-radius: 999rpx;
|
||||
background: linear-gradient(135deg, rgba(79, 70, 229, 0.12) 0%, rgba(124, 58, 237, 0.16) 100%);
|
||||
color: #4f46e5;
|
||||
font-size: 22rpx;
|
||||
font-weight: 600;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.version-picker-close {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
border-radius: 50%;
|
||||
background: #f3f4f6;
|
||||
background: #f1f5f9;
|
||||
color: #6b7280;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 34rpx;
|
||||
font-size: 32rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.version-picker-title {
|
||||
text-align: center;
|
||||
font-size: 36rpx;
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
margin-top: 12rpx;
|
||||
margin-top: 18rpx;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.version-picker-current {
|
||||
margin-top: 16rpx;
|
||||
text-align: center;
|
||||
font-size: 24rpx;
|
||||
color: #475569;
|
||||
background: #f8fafc;
|
||||
border-radius: 999rpx;
|
||||
padding: 10rpx 18rpx;
|
||||
}
|
||||
|
||||
.version-picker-current-em {
|
||||
color: #4f46e5;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.version-picker-desc {
|
||||
margin-top: 12rpx;
|
||||
margin-top: 14rpx;
|
||||
text-align: center;
|
||||
font-size: 24rpx;
|
||||
font-size: 23rpx;
|
||||
color: #6b7280;
|
||||
line-height: 1.6;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.version-picker-actions {
|
||||
margin-top: 28rpx;
|
||||
margin-top: 24rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
gap: 14rpx;
|
||||
}
|
||||
|
||||
.version-btn::after,
|
||||
.version-cancel-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.version-btn,
|
||||
.version-cancel-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
line-height: 1.25;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.version-btn {
|
||||
height: 84rpx;
|
||||
line-height: 84rpx;
|
||||
height: 82rpx;
|
||||
width: 100%;
|
||||
border-radius: 999rpx;
|
||||
color: #fff;
|
||||
font-size: 29rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
border: none;
|
||||
box-shadow: 0 8rpx 22rpx rgba(79, 70, 229, 0.22);
|
||||
box-shadow: 0 10rpx 20rpx rgba(79, 70, 229, 0.2);
|
||||
}
|
||||
|
||||
.version-btn-is-current {
|
||||
transform: translateY(-1rpx);
|
||||
box-shadow: 0 0 0 4rpx #ffffff, 0 0 0 6rpx rgba(79, 70, 229, 0.45), 0 12rpx 24rpx rgba(79, 70, 229, 0.24);
|
||||
}
|
||||
|
||||
.version-btn-personal { background: linear-gradient(135deg, #ef4444 0%, #f97316 100%); }
|
||||
@@ -339,7 +379,6 @@
|
||||
|
||||
.version-cancel-btn {
|
||||
height: 76rpx;
|
||||
line-height: 76rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #f3f4f6;
|
||||
color: #6b7280;
|
||||
|
||||
@@ -10,7 +10,9 @@ Page({
|
||||
maintenanceMode: false,
|
||||
reviewMode: false,
|
||||
permFace: true,
|
||||
showVersionPicker: false
|
||||
showVersionPicker: false,
|
||||
versionPickerCurrent: 'gaokao',
|
||||
versionPickerCurrentLabel: '高考版'
|
||||
},
|
||||
|
||||
_navigateByVersion(version) {
|
||||
@@ -30,7 +32,11 @@ Page({
|
||||
},
|
||||
|
||||
openVersionPicker() {
|
||||
this.setData({ showVersionPicker: true })
|
||||
this.setData({
|
||||
showVersionPicker: true,
|
||||
versionPickerCurrent: 'gaokao',
|
||||
versionPickerCurrentLabel: '高考版'
|
||||
})
|
||||
},
|
||||
|
||||
closeVersionPicker() {
|
||||
|
||||
@@ -84,14 +84,12 @@
|
||||
<view class="version-picker-close" bindtap="closeVersionPicker">×</view>
|
||||
</view>
|
||||
<view class="version-picker-title">请选择使用版本</view>
|
||||
<view class="version-picker-current">当前入口:<text class="version-picker-current-em">{{versionPickerCurrentLabel}}</text></view>
|
||||
<view class="version-picker-desc">当前企业支持三种版本,选择后将进入对应流程</view>
|
||||
<view class="version-picker-actions">
|
||||
<button class="version-btn version-btn-personal" data-version="personal" bindtap="selectVersion">个人版</button>
|
||||
<button class="version-btn version-btn-enterprise" data-version="enterprise" bindtap="selectVersion">企业版</button>
|
||||
<button class="version-btn version-btn-gaokao" data-version="gaokao" bindtap="selectVersion">高考版</button>
|
||||
</view>
|
||||
<view class="version-picker-foot">
|
||||
<button class="version-cancel-btn" bindtap="closeVersionPicker">取消</button>
|
||||
<button class="version-btn version-btn-personal {{versionPickerCurrent === 'personal' ? 'version-btn-is-current' : ''}}" data-version="personal" bindtap="selectVersion">个人版</button>
|
||||
<button class="version-btn version-btn-enterprise {{versionPickerCurrent === 'enterprise' ? 'version-btn-is-current' : ''}}" data-version="enterprise" bindtap="selectVersion">企业版</button>
|
||||
<button class="version-btn version-btn-gaokao {{versionPickerCurrent === 'gaokao' ? 'version-btn-is-current' : ''}}" data-version="gaokao" bindtap="selectVersion">高考版</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -95,17 +95,19 @@
|
||||
|
||||
.top-image-section {
|
||||
width: 100%;
|
||||
padding: 15rpx 40rpx 20rpx;
|
||||
padding: 8rpx 40rpx 10rpx;
|
||||
flex-shrink: 0;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
margin-top: 0;
|
||||
margin-top: -20rpx;
|
||||
}
|
||||
|
||||
.image-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
transform: translateY(-26rpx);
|
||||
margin-bottom: -26rpx;
|
||||
}
|
||||
|
||||
.image-wrapper {
|
||||
@@ -160,7 +162,7 @@
|
||||
}
|
||||
|
||||
.process-section {
|
||||
padding: 15rpx 40rpx 20rpx;
|
||||
padding: 8rpx 40rpx 20rpx;
|
||||
flex-shrink: 0;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
@@ -273,7 +275,7 @@
|
||||
.version-picker-mask {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(10, 15, 30, 0.52);
|
||||
background: rgba(10, 15, 30, 0.44);
|
||||
z-index: 20000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -284,11 +286,12 @@
|
||||
|
||||
.version-picker-dialog {
|
||||
width: 100%;
|
||||
max-width: 640rpx;
|
||||
background: #fff;
|
||||
border-radius: 30rpx;
|
||||
padding: 26rpx 30rpx 24rpx;
|
||||
box-shadow: 0 24rpx 70rpx rgba(16, 24, 40, 0.28);
|
||||
max-width: 620rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 36rpx;
|
||||
padding: 30rpx 30rpx 30rpx;
|
||||
border: 1rpx solid rgba(99, 102, 241, 0.12);
|
||||
box-shadow: 0 30rpx 80rpx rgba(15, 23, 42, 0.22);
|
||||
}
|
||||
|
||||
.version-picker-head {
|
||||
@@ -298,64 +301,101 @@
|
||||
}
|
||||
|
||||
.version-picker-badge {
|
||||
padding: 8rpx 18rpx;
|
||||
padding: 8rpx 20rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #e8f0ff;
|
||||
color: #1d4ed8;
|
||||
background: linear-gradient(135deg, rgba(79, 70, 229, 0.12) 0%, rgba(124, 58, 237, 0.16) 100%);
|
||||
color: #4f46e5;
|
||||
font-size: 22rpx;
|
||||
font-weight: 600;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.version-picker-close {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
border-radius: 50%;
|
||||
background: #f3f4f6;
|
||||
background: #f1f5f9;
|
||||
color: #6b7280;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 34rpx;
|
||||
font-size: 32rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.version-picker-title {
|
||||
text-align: center;
|
||||
font-size: 36rpx;
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
margin-top: 12rpx;
|
||||
margin-top: 18rpx;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.version-picker-current {
|
||||
margin-top: 16rpx;
|
||||
text-align: center;
|
||||
font-size: 24rpx;
|
||||
color: #475569;
|
||||
background: #f8fafc;
|
||||
border-radius: 999rpx;
|
||||
padding: 10rpx 18rpx;
|
||||
}
|
||||
|
||||
.version-picker-current-em {
|
||||
color: #4f46e5;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.version-picker-desc {
|
||||
margin-top: 12rpx;
|
||||
margin-top: 14rpx;
|
||||
text-align: center;
|
||||
font-size: 24rpx;
|
||||
font-size: 23rpx;
|
||||
color: #6b7280;
|
||||
line-height: 1.6;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.version-picker-actions {
|
||||
margin-top: 28rpx;
|
||||
margin-top: 24rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
gap: 14rpx;
|
||||
}
|
||||
|
||||
.version-btn::after,
|
||||
.version-cancel-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.version-btn,
|
||||
.version-cancel-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
line-height: 1.25;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.version-btn {
|
||||
height: 84rpx;
|
||||
line-height: 84rpx;
|
||||
height: 82rpx;
|
||||
width: 100%;
|
||||
border-radius: 999rpx;
|
||||
color: #fff;
|
||||
font-size: 29rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
border: none;
|
||||
box-shadow: 0 6rpx 16rpx rgba(37, 99, 235, 0.16);
|
||||
box-shadow: 0 10rpx 20rpx rgba(79, 70, 229, 0.2);
|
||||
}
|
||||
|
||||
.version-btn-personal { background: #2563eb; }
|
||||
.version-btn-enterprise { background: #2563eb; }
|
||||
.version-btn-gaokao { background: #2563eb; }
|
||||
.version-btn-is-current {
|
||||
transform: translateY(-1rpx);
|
||||
box-shadow: 0 0 0 4rpx #ffffff, 0 0 0 6rpx rgba(79, 70, 229, 0.45), 0 12rpx 24rpx rgba(79, 70, 229, 0.24);
|
||||
}
|
||||
|
||||
.version-btn-personal { background: linear-gradient(135deg, #ef4444 0%, #f97316 100%); }
|
||||
.version-btn-enterprise { background: linear-gradient(135deg, #2563eb 0%, #6366f1 100%); }
|
||||
.version-btn-gaokao { background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%); }
|
||||
|
||||
.version-picker-foot {
|
||||
margin-top: 14rpx;
|
||||
@@ -363,7 +403,6 @@
|
||||
|
||||
.version-cancel-btn {
|
||||
height: 76rpx;
|
||||
line-height: 76rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #f3f4f6;
|
||||
color: #4b5563;
|
||||
|
||||
@@ -12,7 +12,9 @@ Page({
|
||||
aiAnalysisText: '分析',
|
||||
reviewMode: true,
|
||||
permFace: true,
|
||||
showVersionPicker: false
|
||||
showVersionPicker: false,
|
||||
versionPickerCurrent: 'personal',
|
||||
versionPickerCurrentLabel: '个人版'
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
@@ -206,7 +208,11 @@ Page({
|
||||
},
|
||||
|
||||
openVersionPicker() {
|
||||
this.setData({ showVersionPicker: true })
|
||||
this.setData({
|
||||
showVersionPicker: true,
|
||||
versionPickerCurrent: 'personal',
|
||||
versionPickerCurrentLabel: '个人版'
|
||||
})
|
||||
},
|
||||
|
||||
// 切换版本:2 个版本沿用原逻辑,3 个版本弹出居中选择框
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<view class="navbar-content">
|
||||
<view class="switch-enterprise-btn" wx:if="{{showEnterpriseEntry && !reviewMode}}" bindtap="switchToEnterprise">
|
||||
<text class="enterprise-icon">🏢</text>
|
||||
<text class="enterprise-text">企业版</text>
|
||||
<text class="enterprise-text">个人版</text>
|
||||
</view>
|
||||
<view class="navbar-title">{{siteTitle || '神仙团队性格测试'}}</view>
|
||||
<view class="navbar-placeholder"></view>
|
||||
@@ -84,14 +84,12 @@
|
||||
<view class="version-picker-close" bindtap="closeVersionPicker">×</view>
|
||||
</view>
|
||||
<view class="version-picker-title">请选择使用版本</view>
|
||||
<view class="version-picker-current">当前入口:<text class="version-picker-current-em">{{versionPickerCurrentLabel}}</text></view>
|
||||
<view class="version-picker-desc">当前企业支持三种版本,选择后将进入对应流程</view>
|
||||
<view class="version-picker-actions">
|
||||
<button class="version-btn version-btn-personal" data-version="personal" bindtap="selectVersion">个人版</button>
|
||||
<button class="version-btn version-btn-enterprise" data-version="enterprise" bindtap="selectVersion">企业版</button>
|
||||
<button class="version-btn version-btn-gaokao" data-version="gaokao" bindtap="selectVersion">高考版</button>
|
||||
</view>
|
||||
<view class="version-picker-foot">
|
||||
<button class="version-cancel-btn" bindtap="closeVersionPicker">取消</button>
|
||||
<button class="version-btn version-btn-personal {{versionPickerCurrent === 'personal' ? 'version-btn-is-current' : ''}}" data-version="personal" bindtap="selectVersion">个人版</button>
|
||||
<button class="version-btn version-btn-enterprise {{versionPickerCurrent === 'enterprise' ? 'version-btn-is-current' : ''}}" data-version="enterprise" bindtap="selectVersion">企业版</button>
|
||||
<button class="version-btn version-btn-gaokao {{versionPickerCurrent === 'gaokao' ? 'version-btn-is-current' : ''}}" data-version="gaokao" bindtap="selectVersion">高考版</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -254,7 +254,7 @@
|
||||
.version-picker-mask {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: rgba(10, 15, 30, 0.52);
|
||||
background: rgba(10, 15, 30, 0.44);
|
||||
z-index: 20000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -265,11 +265,12 @@
|
||||
|
||||
.version-picker-dialog {
|
||||
width: 100%;
|
||||
max-width: 640rpx;
|
||||
background: #fff;
|
||||
border-radius: 30rpx;
|
||||
padding: 26rpx 30rpx 24rpx;
|
||||
box-shadow: 0 24rpx 70rpx rgba(16, 24, 40, 0.28);
|
||||
max-width: 620rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 36rpx;
|
||||
padding: 30rpx 30rpx 30rpx;
|
||||
border: 1rpx solid rgba(99, 102, 241, 0.12);
|
||||
box-shadow: 0 30rpx 80rpx rgba(15, 23, 42, 0.22);
|
||||
}
|
||||
|
||||
.version-picker-head {
|
||||
@@ -279,59 +280,96 @@
|
||||
}
|
||||
|
||||
.version-picker-badge {
|
||||
padding: 8rpx 18rpx;
|
||||
padding: 8rpx 20rpx;
|
||||
border-radius: 999rpx;
|
||||
background: linear-gradient(135deg, rgba(79, 70, 229, 0.12) 0%, rgba(124, 58, 237, 0.16) 100%);
|
||||
color: #4f46e5;
|
||||
font-size: 22rpx;
|
||||
font-weight: 600;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.version-picker-close {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
width: 52rpx;
|
||||
height: 52rpx;
|
||||
border-radius: 50%;
|
||||
background: #f3f4f6;
|
||||
background: #f1f5f9;
|
||||
color: #6b7280;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 34rpx;
|
||||
font-size: 32rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.version-picker-title {
|
||||
text-align: center;
|
||||
font-size: 36rpx;
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
margin-top: 12rpx;
|
||||
margin-top: 18rpx;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.version-picker-current {
|
||||
margin-top: 16rpx;
|
||||
text-align: center;
|
||||
font-size: 24rpx;
|
||||
color: #475569;
|
||||
background: #f8fafc;
|
||||
border-radius: 999rpx;
|
||||
padding: 10rpx 18rpx;
|
||||
}
|
||||
|
||||
.version-picker-current-em {
|
||||
color: #4f46e5;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.version-picker-desc {
|
||||
margin-top: 12rpx;
|
||||
margin-top: 14rpx;
|
||||
text-align: center;
|
||||
font-size: 24rpx;
|
||||
font-size: 23rpx;
|
||||
color: #6b7280;
|
||||
line-height: 1.6;
|
||||
line-height: 1.55;
|
||||
}
|
||||
|
||||
.version-picker-actions {
|
||||
margin-top: 28rpx;
|
||||
margin-top: 24rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
gap: 14rpx;
|
||||
}
|
||||
|
||||
.version-btn::after,
|
||||
.version-cancel-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.version-btn,
|
||||
.version-cancel-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
line-height: 1.25;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.version-btn {
|
||||
height: 84rpx;
|
||||
line-height: 84rpx;
|
||||
height: 82rpx;
|
||||
width: 100%;
|
||||
border-radius: 999rpx;
|
||||
color: #fff;
|
||||
font-size: 29rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
border: none;
|
||||
box-shadow: 0 8rpx 22rpx rgba(79, 70, 229, 0.22);
|
||||
box-shadow: 0 10rpx 20rpx rgba(79, 70, 229, 0.2);
|
||||
}
|
||||
|
||||
.version-btn-is-current {
|
||||
transform: translateY(-1rpx);
|
||||
box-shadow: 0 0 0 4rpx #ffffff, 0 0 0 6rpx rgba(79, 70, 229, 0.45), 0 12rpx 24rpx rgba(79, 70, 229, 0.24);
|
||||
}
|
||||
|
||||
.version-btn-personal { background: linear-gradient(135deg, #ef4444 0%, #f97316 100%); }
|
||||
@@ -344,7 +382,6 @@
|
||||
|
||||
.version-cancel-btn {
|
||||
height: 76rpx;
|
||||
line-height: 76rpx;
|
||||
border-radius: 999rpx;
|
||||
background: #f3f4f6;
|
||||
color: #6b7280;
|
||||
|
||||
@@ -87,6 +87,8 @@ Page({
|
||||
profileRecoJump: null,
|
||||
/** 拉取自 /api/distribution/my-invite-code,与推广中心一致 */
|
||||
myInviteCode: '',
|
||||
myInviteCodeNumeric: '',
|
||||
myInviteCodeLegacy: '',
|
||||
myInviteCodeLoadState: 'idle',
|
||||
myInviteCodeErrMsg: '',
|
||||
myInviteCodeHint: '',
|
||||
@@ -259,6 +261,8 @@ Page({
|
||||
profileRecoSectionLabel: '',
|
||||
profileRecoJump: null,
|
||||
myInviteCode: '',
|
||||
myInviteCodeNumeric: '',
|
||||
myInviteCodeLegacy: '',
|
||||
myInviteCodeLoadState: 'idle',
|
||||
myInviteCodeErrMsg: '',
|
||||
myInviteCodeHint: '',
|
||||
@@ -290,6 +294,8 @@ Page({
|
||||
if (!token || !this.data.permDistribution) {
|
||||
this.setData({
|
||||
myInviteCode: '',
|
||||
myInviteCodeNumeric: '',
|
||||
myInviteCodeLegacy: '',
|
||||
myInviteCodeLoadState: 'idle',
|
||||
myInviteCodeErrMsg: '',
|
||||
myInviteCodeHint: ''
|
||||
@@ -313,6 +319,8 @@ Page({
|
||||
(typeof res.statusCode === 'number' ? `请求失败 (${res.statusCode})` : '加载失败')
|
||||
this.setData({
|
||||
myInviteCode: '',
|
||||
myInviteCodeNumeric: '',
|
||||
myInviteCodeLegacy: '',
|
||||
myInviteCodeLoadState: 'error',
|
||||
myInviteCodeErrMsg: msg,
|
||||
myInviteCodeHint: ''
|
||||
@@ -321,11 +329,22 @@ Page({
|
||||
}
|
||||
const data = payload.data || {}
|
||||
const raw = data.code != null ? String(data.code).trim() : ''
|
||||
const code = raw ? raw.toUpperCase() : ''
|
||||
const code = raw ? (/^[0-9]+$/.test(raw) ? raw : raw.toUpperCase()) : ''
|
||||
const numRaw =
|
||||
data.numericCode != null && String(data.numericCode).trim() !== ''
|
||||
? String(data.numericCode).trim()
|
||||
: ''
|
||||
const legRaw =
|
||||
data.legacyCode != null && String(data.legacyCode).trim() !== ''
|
||||
? String(data.legacyCode).trim().toUpperCase()
|
||||
: ''
|
||||
const hint = (data.hint && String(data.hint).trim()) || ''
|
||||
if (code) {
|
||||
if (code || numRaw || legRaw) {
|
||||
this.setData({
|
||||
myInviteCode: code,
|
||||
/* 默认展示:数字码优先 */
|
||||
myInviteCode: numRaw || legRaw || code,
|
||||
myInviteCodeNumeric: numRaw,
|
||||
myInviteCodeLegacy: legRaw,
|
||||
myInviteCodeLoadState: 'ready',
|
||||
myInviteCodeErrMsg: '',
|
||||
myInviteCodeHint: ''
|
||||
@@ -333,6 +352,8 @@ Page({
|
||||
} else {
|
||||
this.setData({
|
||||
myInviteCode: '',
|
||||
myInviteCodeNumeric: '',
|
||||
myInviteCodeLegacy: '',
|
||||
myInviteCodeLoadState: 'nodata',
|
||||
myInviteCodeErrMsg: '',
|
||||
myInviteCodeHint: hint || '暂无可用邀请码'
|
||||
@@ -342,6 +363,8 @@ Page({
|
||||
fail: () =>
|
||||
this.setData({
|
||||
myInviteCode: '',
|
||||
myInviteCodeNumeric: '',
|
||||
myInviteCodeLegacy: '',
|
||||
myInviteCodeLoadState: 'error',
|
||||
myInviteCodeErrMsg: '网络异常',
|
||||
myInviteCodeHint: ''
|
||||
@@ -358,11 +381,13 @@ Page({
|
||||
},
|
||||
|
||||
copyMyInviteCode() {
|
||||
const code = (this.data.myInviteCode || '').trim()
|
||||
if (!code) return
|
||||
const n = (this.data.myInviteCodeNumeric || '').trim()
|
||||
const l = (this.data.myInviteCodeLegacy || '').trim()
|
||||
const text = n || l || (this.data.myInviteCode || '').trim()
|
||||
if (!text) return
|
||||
wx.setClipboardData({
|
||||
data: code,
|
||||
success: () => wx.showToast({ title: '已复制邀请码', icon: 'success' })
|
||||
data: text,
|
||||
success: () => wx.showToast({ title: n ? '已复制数字码' : '已复制邀请码', icon: 'success' })
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
<text class="invite-strip__label">我的邀请码</text>
|
||||
<text wx:if="{{myInviteCodeLoadState === 'loading'}}" class="invite-strip__muted">加载中…</text>
|
||||
<text wx:elif="{{myInviteCodeLoadState === 'error'}}" class="invite-strip__err">{{myInviteCodeErrMsg}}</text>
|
||||
<text wx:elif="{{myInviteCodeLoadState === 'ready' && myInviteCode}}" class="invite-strip__code">{{myInviteCode}}</text>
|
||||
<text wx:elif="{{myInviteCodeLoadState === 'ready' && (myInviteCodeNumeric || myInviteCode)}}" class="invite-strip__code">{{myInviteCodeNumeric || myInviteCode}}</text>
|
||||
<text wx:else class="invite-strip__err">{{myInviteCodeHint}}</text>
|
||||
</view>
|
||||
<view class="invite-strip__side">
|
||||
|
||||
@@ -34,6 +34,9 @@ Page({
|
||||
withdrawFeeYuan: '0.00',
|
||||
withdrawActualYuan: '0.00',
|
||||
myInviteCode: '',
|
||||
/** 与接口 numericCode / legacyCode 对应,便于分开展示与复制 */
|
||||
myInviteCodeNumeric: '',
|
||||
myInviteCodeLegacy: '',
|
||||
myInviteCodeMeta: null,
|
||||
/** loading | ready | error | nodata — 避免因接口失败整块不渲染 */
|
||||
myInviteCodeLoadState: 'loading',
|
||||
@@ -91,6 +94,8 @@ Page({
|
||||
(typeof res.statusCode === 'number' ? `请求失败 (${res.statusCode})` : '加载失败')
|
||||
this.setData({
|
||||
myInviteCode: '',
|
||||
myInviteCodeNumeric: '',
|
||||
myInviteCodeLegacy: '',
|
||||
myInviteCodeMeta: null,
|
||||
myInviteCodeLoadState: 'error',
|
||||
myInviteCodeErrMsg: msg,
|
||||
@@ -100,11 +105,22 @@ Page({
|
||||
}
|
||||
const data = payload.data || {}
|
||||
const raw = data.code != null ? String(data.code).trim() : ''
|
||||
const code = raw ? raw.toUpperCase() : ''
|
||||
const code = raw ? (/^[0-9]+$/.test(raw) ? raw : raw.toUpperCase()) : ''
|
||||
const numRaw =
|
||||
data.numericCode != null && String(data.numericCode).trim() !== ''
|
||||
? String(data.numericCode).trim()
|
||||
: ''
|
||||
const legRaw =
|
||||
data.legacyCode != null && String(data.legacyCode).trim() !== ''
|
||||
? String(data.legacyCode).trim().toUpperCase()
|
||||
: ''
|
||||
const hint = (data.hint && String(data.hint).trim()) || ''
|
||||
if (code) {
|
||||
if (code || numRaw || legRaw) {
|
||||
this.setData({
|
||||
myInviteCode: code,
|
||||
/* 默认展示与复制优先级:数字码 > 老版 > 接口 code */
|
||||
myInviteCode: numRaw || legRaw || code,
|
||||
myInviteCodeNumeric: numRaw,
|
||||
myInviteCodeLegacy: legRaw,
|
||||
myInviteCodeMeta: data,
|
||||
myInviteCodeLoadState: 'ready',
|
||||
myInviteCodeErrMsg: '',
|
||||
@@ -113,6 +129,8 @@ Page({
|
||||
} else {
|
||||
this.setData({
|
||||
myInviteCode: '',
|
||||
myInviteCodeNumeric: '',
|
||||
myInviteCodeLegacy: '',
|
||||
myInviteCodeMeta: data,
|
||||
myInviteCodeLoadState: 'nodata',
|
||||
myInviteCodeErrMsg: '',
|
||||
@@ -123,6 +141,8 @@ Page({
|
||||
fail: () => {
|
||||
this.setData({
|
||||
myInviteCode: '',
|
||||
myInviteCodeNumeric: '',
|
||||
myInviteCodeLegacy: '',
|
||||
myInviteCodeMeta: null,
|
||||
myInviteCodeLoadState: 'error',
|
||||
myInviteCodeErrMsg: '网络异常,请稍后重试',
|
||||
@@ -137,11 +157,31 @@ Page({
|
||||
},
|
||||
|
||||
copyMyInviteCode() {
|
||||
const code = (this.data.myInviteCode || '').trim()
|
||||
if (!code) return
|
||||
const n = (this.data.myInviteCodeNumeric || '').trim()
|
||||
const l = (this.data.myInviteCodeLegacy || '').trim()
|
||||
const text = n || l || (this.data.myInviteCode || '').trim()
|
||||
if (!text) return
|
||||
wx.setClipboardData({
|
||||
data: code,
|
||||
success: () => wx.showToast({ title: '已复制邀请码', icon: 'success' })
|
||||
data: text,
|
||||
success: () => wx.showToast({ title: n ? '已复制数字码' : '已复制邀请码', icon: 'success' })
|
||||
})
|
||||
},
|
||||
|
||||
copyMyInviteCodeNumeric() {
|
||||
const n = (this.data.myInviteCodeNumeric || '').trim()
|
||||
if (!n) return
|
||||
wx.setClipboardData({
|
||||
data: n,
|
||||
success: () => wx.showToast({ title: '已复制数字码', icon: 'success' })
|
||||
})
|
||||
},
|
||||
|
||||
copyMyInviteCodeLegacy() {
|
||||
const l = (this.data.myInviteCodeLegacy || '').trim()
|
||||
if (!l) return
|
||||
wx.setClipboardData({
|
||||
data: l,
|
||||
success: () => wx.showToast({ title: '已复制老版码', icon: 'success' })
|
||||
})
|
||||
},
|
||||
|
||||
|
||||
@@ -35,7 +35,21 @@
|
||||
<view class="my-invite-card">
|
||||
<view class="my-invite-card__head">
|
||||
<text class="my-invite-card__title">我的邀请码</text>
|
||||
<view wx:if="{{myInviteCodeLoadState === 'ready' && myInviteCode}}" class="my-invite-card__copy" bindtap="copyMyInviteCode">复制</view>
|
||||
<view
|
||||
wx:if="{{myInviteCodeLoadState === 'ready' && myInviteCodeNumeric}}"
|
||||
class="my-invite-card__copy"
|
||||
bindtap="copyMyInviteCodeNumeric"
|
||||
>复制邀请码</view>
|
||||
<view
|
||||
wx:elif="{{myInviteCodeLoadState === 'ready' && !myInviteCodeNumeric && myInviteCodeLegacy}}"
|
||||
class="my-invite-card__copy"
|
||||
bindtap="copyMyInviteCodeLegacy"
|
||||
>复制老版码</view>
|
||||
<view
|
||||
wx:elif="{{myInviteCodeLoadState === 'ready' && myInviteCode}}"
|
||||
class="my-invite-card__copy"
|
||||
bindtap="copyMyInviteCode"
|
||||
>复制</view>
|
||||
<view wx:elif="{{myInviteCodeLoadState === 'error'}}" class="my-invite-card__retry" bindtap="retryMyInviteCode">重试</view>
|
||||
</view>
|
||||
<block wx:if="{{myInviteCodeLoadState === 'loading'}}">
|
||||
@@ -45,9 +59,13 @@
|
||||
<text class="my-invite-card__err">{{myInviteCodeErrMsg}}</text>
|
||||
<text class="my-invite-card__tip">若提示功能未就绪,请在数据库执行 api/database/add_invite_codes.sql 建表后再试。</text>
|
||||
</block>
|
||||
<block wx:elif="{{myInviteCodeLoadState === 'ready' && myInviteCode}}">
|
||||
<text class="my-invite-card__code" user-select="true">{{myInviteCode}}</text>
|
||||
<text class="my-invite-card__tip">好友在付费解锁前填写此码,即可与你建立推广绑定</text>
|
||||
<block wx:elif="{{myInviteCodeLoadState === 'ready' && (myInviteCode || myInviteCodeNumeric || myInviteCodeLegacy)}}">
|
||||
<view wx:if="{{myInviteCodeNumeric}}" class="my-invite-card__numeric-hero">
|
||||
<text class="my-invite-card__numeric-caption">我的邀请码</text>
|
||||
<text class="my-invite-card__code" user-select="true">{{myInviteCodeNumeric}}</text>
|
||||
</view>
|
||||
<text wx:if="{{!myInviteCodeNumeric && myInviteCode}}" class="my-invite-card__code" user-select="true">{{myInviteCode}}</text>
|
||||
<text class="my-invite-card__tip">好友在付费解锁前填写此邀请码,即可与你建立推广绑定。</text>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<text class="my-invite-card__err">{{myInviteCodeHint}}</text>
|
||||
|
||||
@@ -47,6 +47,47 @@ page {
|
||||
background: #fff1f2;
|
||||
border-radius: 999rpx;
|
||||
}
|
||||
.my-invite-card__dual {
|
||||
margin-bottom: 22rpx;
|
||||
}
|
||||
.my-invite-card__dual:last-of-type {
|
||||
margin-bottom: 14rpx;
|
||||
}
|
||||
.my-invite-card__dual-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
.my-invite-card__dual-label {
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
color: #64748b;
|
||||
}
|
||||
.my-invite-card__copy-sm {
|
||||
font-size: 22rpx;
|
||||
font-weight: 600;
|
||||
color: #e11d48;
|
||||
padding: 6rpx 18rpx;
|
||||
background: #fff1f2;
|
||||
border-radius: 999rpx;
|
||||
}
|
||||
.my-invite-card__dual-code {
|
||||
display: block;
|
||||
font-size: 34rpx;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.08em;
|
||||
color: #0f172a;
|
||||
}
|
||||
.my-invite-card__numeric-hero {
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
.my-invite-card__numeric-caption {
|
||||
display: block;
|
||||
font-size: 22rpx;
|
||||
color: #64748b;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
.my-invite-card__code {
|
||||
display: block;
|
||||
font-size: 40rpx;
|
||||
|
||||
Reference in New Issue
Block a user