This commit is contained in:
sjk
2026-01-07 12:18:55 +08:00
parent a7305908de
commit cb267e8d5e
18 changed files with 411 additions and 133 deletions

View File

@@ -497,6 +497,83 @@ class XHSLoginService:
except Exception as e: except Exception as e:
print(f"关闭浏览器异常: {str(e)}", file=sys.stderr) print(f"关闭浏览器异常: {str(e)}", file=sys.stderr)
async def extract_verification_qrcode(self) -> Optional[str]:
"""
提取验证页面的二维码图片
Returns:
二维码图片的base64数据如果提取失败则返回none
"""
try:
if not self.page:
return None
print("正在提取验证二维码...", file=sys.stderr)
# 尝试查找二维码图片元素
qrcode_selectors = [
'.qrcode-img', # 根据您提供的HTML
'img.qrcode-img',
'.qrcode-container img',
'img[src*="data:image"]', # base64图片
'img[src*="qrcode"]',
'img[alt*="二维码"]',
'img[alt*="qrcode"]',
]
for selector in qrcode_selectors:
try:
qrcode_img = await self.page.wait_for_selector(selector, timeout=3000)
if qrcode_img:
print(f"✅ 找到二维码图片: {selector}", file=sys.stderr)
# 获取图片src属性
src = await qrcode_img.get_attribute('src')
if src:
# 如果是base64格式直接返回
if src.startswith('data:image'):
print("✅ 二维码已是base64格式直接返回", file=sys.stderr)
return src
# 如果是URL尝试下载并转换为base64
print(f"二维码是URL格式: {src[:100]}...", file=sys.stderr)
try:
async with aiohttp.ClientSession() as session:
async with session.get(src, timeout=aiohttp.ClientTimeout(total=10)) as response:
if response.status == 200:
img_data = await response.read()
import base64
img_base64 = base64.b64encode(img_data).decode('utf-8')
# 根据内容类型确定格式
content_type = response.headers.get('Content-Type', 'image/png')
base64_str = f"data:{content_type};base64,{img_base64}"
print("✅ 成功下载并转换为base64", file=sys.stderr)
return base64_str
except Exception as e:
print(f"⚠️ 下载二维码图片失败: {str(e)}", file=sys.stderr)
# 如果src方法失败尝试截图
print("尝试截取二维码区域...", file=sys.stderr)
screenshot_bytes = await qrcode_img.screenshot()
if screenshot_bytes:
import base64
img_base64 = base64.b64encode(screenshot_bytes).decode('utf-8')
base64_str = f"data:image/png;base64,{img_base64}"
print("✅ 成功截取二维码并转换为base64", file=sys.stderr)
return base64_str
break
except Exception as e:
print(f"尝试选择器 {selector} 失败: {str(e)}", file=sys.stderr)
continue
print("⚠️ 未找到二维码图片", file=sys.stderr)
return None
except Exception as e:
print(f"⚠️ 提取二维码失败: {str(e)}", file=sys.stderr)
return None
async def send_verification_code(self, phone: str, country_code: str = "+86", login_page: str = "creator") -> Dict[str, Any]: async def send_verification_code(self, phone: str, country_code: str = "+86", login_page: str = "creator") -> Dict[str, Any]:
""" """
发送验证码 发送验证码
@@ -819,16 +896,32 @@ class XHSLoginService:
await send_code_btn.click() await send_code_btn.click()
print("✅ 已点击发送验证码", file=sys.stderr) print("✅ 已点击发送验证码", file=sys.stderr)
# # 优化:简化二次协议处理 # 等待页面响应,检测是否出现验证二维码
# await asyncio.sleep(0.3) # 等待协议弹窗可能出现 await asyncio.sleep(1.5)
# try:
# agreement_btn = await self.page.query_selector('text="同意并继续"') # 检查当前页面URL是否包含captcha验证页面
# if agreement_btn: current_url = self.page.url
# await agreement_btn.click() if 'captcha' in current_url or 'verify' in current_url:
# print(f"✅ 再次点击协议按钮", file=sys.stderr) print(f"⚠️ 检测到验证页面: {current_url}", file=sys.stderr)
# await asyncio.sleep(0.2)
# except Exception: # 尝试提取二维码图片
# pass # 无二次协议弹窗 qrcode_data = await self.extract_verification_qrcode()
if qrcode_data:
print("✅ 成功提取验证二维码", file=sys.stderr)
return {
"success": False,
"need_captcha": True,
"captcha_type": "qrcode",
"qrcode_image": qrcode_data,
"message": "需要扫码验证请使用小红书APP扫描二维码"
}
else:
return {
"success": False,
"need_captcha": True,
"captcha_type": "unknown",
"message": "出现验证码验证,请稍后重试"
}
# 直接返回成功,不再检测滑块 # 直接返回成功,不再检测滑块
print("\n✅ 验证码发送流程完成,请查看手机短信", file=sys.stderr) print("\n✅ 验证码发送流程完成,请查看手机短信", file=sys.stderr)

View File

@@ -346,8 +346,30 @@ func (s *EmployeeService) asyncBindXHS(employeeID int, xhsPhone, code string) {
return fmt.Errorf("小红书登录失败: %w", err) return fmt.Errorf("小红书登录失败: %w", err)
} }
// 检Python服务返回结果 // 检Python服务返回结果
if loginResult.Code != 0 { if loginResult.Code != 0 {
// 检查是否需要扫码验证
if needCaptcha, ok := loginResult.Data["need_captcha"].(bool); ok && needCaptcha {
// 出现验证码,更新绑定状态为"need_captcha"
captchaData := map[string]interface{}{
"status": "need_captcha",
"captcha_type": loginResult.Data["captcha_type"],
"message": loginResult.Data["message"],
}
// 如果有二维码图片,也一并返回
if qrcodeImage, ok := loginResult.Data["qrcode_image"].(string); ok {
captchaData["qrcode_image"] = qrcodeImage
}
// 将captchaData序列化并存入Redis
captchaJSON, _ := json.Marshal(captchaData)
if err := database.RDB.Set(ctx, bindStatusKey, string(captchaJSON), 180*time.Second).Err(); err != nil {
log.Printf("绑定小红书 - 用户%d - 更新验证状态失败: %v", employeeID, err)
}
log.Printf("绑定小红书 - 用户%d - 需要验证码验证: %s", employeeID, loginResult.Data["captcha_type"])
return fmt.Errorf("需要验证码验证")
}
return fmt.Errorf("小红书登录失败: %s", loginResult.Message) return fmt.Errorf("小红书登录失败: %s", loginResult.Message)
} }
@@ -534,7 +556,7 @@ func (s *EmployeeService) GetBindXHSStatus(employeeID int) (map[string]interface
} }
// 尝试解析JSON状态 // 尝试解析JSON状态
var statusData map[string]string var statusData map[string]interface{}
if err := json.Unmarshal([]byte(statusJSON), &statusData); err != nil { if err := json.Unmarshal([]byte(statusJSON), &statusData); err != nil {
log.Printf("获取绑定状态 - 用户%d - JSON解析失败: %v, 原始数据: %s", employeeID, err, statusJSON) log.Printf("获取绑定状态 - 用户%d - JSON解析失败: %v, 原始数据: %s", employeeID, err, statusJSON)
// 如果不是JSON可能是纯字符串状态 // 如果不是JSON可能是纯字符串状态
@@ -550,17 +572,36 @@ func (s *EmployeeService) GetBindXHSStatus(employeeID int) (map[string]interface
"status": statusData["status"], "status": statusData["status"],
} }
if statusData["status"] == "success" { if status, ok := statusData["status"].(string); ok {
result["xhs_account"] = statusData["xhs_account"] switch status {
case "success":
if xhsAccount, ok := statusData["xhs_account"].(string); ok {
result["xhs_account"] = xhsAccount
}
result["message"] = "绑定成功" result["message"] = "绑定成功"
log.Printf("获取绑定状态 - 用户%d - 绑定成功: %s", employeeID, statusData["xhs_account"]) log.Printf("获取绑定状态 - 用户%d - 绑定成功", employeeID)
} else if statusData["status"] == "failed" { case "failed":
result["error"] = statusData["error"] if errorMsg, ok := statusData["error"].(string); ok {
log.Printf("获取绑定状态 - 用户%d - 绑定失败: %s", employeeID, statusData["error"]) result["error"] = errorMsg
} else if statusData["status"] == "processing" { }
// JSON格式的processing状态 log.Printf("获取绑定状态 - 用户%d - 绑定失败", employeeID)
case "processing":
result["message"] = "正在登录小红书,请稍候..." result["message"] = "正在登录小红书,请稍候..."
log.Printf("获取绑定状态 - 用户%d - 状态: processing (JSON格式)", employeeID) log.Printf("获取绑定状态 - 用户%d - 状态: processing", employeeID)
case "need_captcha":
// 需要验证码验证
if message, ok := statusData["message"].(string); ok {
result["message"] = message
}
if captchaType, ok := statusData["captcha_type"].(string); ok {
result["captcha_type"] = captchaType
}
// 如果有二维码图片,也返回
if qrcodeImage, ok := statusData["qrcode_image"].(string); ok {
result["qrcode_image"] = qrcodeImage
}
log.Printf("获取绑定状态 - 用户%d - 需要验证码: %s", employeeID, statusData["captcha_type"])
}
} }
return result, nil return result, nil

View File

@@ -1,5 +1,5 @@
{ {
"navigationBarTitleText": "隐私政策", "navigationBarTitleText": "隐私政策",
"navigationBarBackgroundColor": "#ff2442", "navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "white" "navigationBarTextStyle": "black"
} }

View File

@@ -1,91 +1,135 @@
<!--pages/agreement/privacy-policy/privacy-policy.wxml--> <!--pages/agreement/privacy-policy/privacy-policy.wxml-->
<view class="agreement-container"> <view class="agreement-container">
<scroll-view class="content-scroll" scroll-y> <scroll-view class="content-scroll" scroll-y="{{true}}" show-scrollbar="{{false}}" enhanced="{{true}}">
<view class="agreement-title">隐私政策</view> <view class="agreement-content">
<view class="update-time">更新时间2024年12月5日</view> <view class="agreement-title">万花筒隐私权协议</view>
<view class="update-time">更新日期2026年 1 月 9 日</view>
<view class="update-time">生效日期2026年 1 月 9 日</view>
<view class="section"> <view class="section">
<view class="section-title">一、信息收集</view>
<view class="section-content"> <view class="section-content">
我们会收集您在使用服务时主动提供或因使用服务而产生的信息,包括但不限于:\n 欢迎您使用【万花筒】,我们高度重视您的隐私保护,本政策将说明我们如何收集、使用、存储及共享您的个人信息,请仔细阅读。
1. 微信授权信息(昵称、头像等)\n
2. 设备信息\n
3. 日志信息\n
4. 位置信息(如您授权)
</view> </view>
</view> </view>
<view class="section"> <view class="section">
<view class="section-title">、信息使用</view> <view class="section-title">、信息的收集与用途</view>
<view class="section-content"> <view class="section-content">
我们收集和使用您的个人信息用于:\n <text class="content-bold">1.必要信息</text>
1. 为您提供、维护和改进我们的服务\n </view>
2. 与您沟通,包括发送通知和更新\n <view class="section-content">
3. 保护服务的安全性和完整性\n · 账号信息:手机号/微信账号(用于注册、登录及身份验证)。
4. 遵守法律法规要求 </view>
<view class="section-content">
· 设备信息设备型号、操作系统、IP地址用于服务适配及安全风控
</view>
<view class="section-content">
<text class="content-bold">2.信息的用途</text>
</view>
<view class="section-content">
· 保障账号安全、防范网络攻击;
</view>
<view class="section-content">
· 优化产品功能及用户体验;
</view>
<view class="section-content">
· 依法履行法定义务(如配合监管调查)。
</view> </view>
</view> </view>
<view class="section"> <view class="section">
<view class="section-title">、信息共享</view> <view class="section-title">、信息共享与披露</view>
<view class="section-content"> <view class="section-content">
我们不会与第三方共享您的个人信息,除非:\n <text class="content-bold">1.共享场景</text>
1. 获得您的明确同意\n </view>
2. 法律法规要求\n <view class="section-content">
3. 与我们的服务提供商共享(仅限于提供服务所必需)\n · 第三方服务商仅为实现服务目的向技术合作方如云服务商、AI模型供应商共享必要信息并要求其严格保密。
4. 保护我们或他人的合法权益 </view>
<view class="section-content">
· 法律要求:根据法律法规、司法或行政机关要求披露。
</view>
<view class="section-content">
· 用户授权:经您单独同意后,向其他方共享信息。
</view>
<view class="section-content">
<text class="content-bold">2.不共享范围</text>
</view>
<view class="section-content">
· 未经用户同意,不会向广告商或其他无关第三方出售、交易您的个人信息。
</view> </view>
</view> </view>
<view class="section"> <view class="section">
<view class="section-title">四、信息安全</view> <view class="section-title">三、数据存储与安全</view>
<view class="section-content"> <view class="section-content">
我们采取各种安全措施来保护您的个人信息,包括:\n <text class="content-bold">1.存储地点</text>
1. 使用加密技术保护数据传输\n </view>
2. 限制员工访问个人信息\n <view class="section-content">
3. 定期审查信息收集、存储和处理实践\n · 在中华人民共和国境内存储,如需跨境传输将另行征得您的同意,并符合相关法律法规。
4. 采取物理和技术措施防止未经授权的访问 </view>
<view class="section-content">
<text class="content-bold">2.存储期限</text>
</view>
<view class="section-content">
· 账号信息保留至您注销账号后、30日】
</view>
<view class="section-content">
· 内容及素材保留至您主动删除或账号注销后、30日】。
</view>
<view class="section-content">
<text class="content-bold">3.安全措施</text>
</view>
<view class="section-content">
· 采用SSL加密、访问权限控制等技术手段保护数据
</view>
<view class="section-content">
· 定期开展安全风险评估,制定应急预案。
</view> </view>
</view> </view>
<view class="section"> <view class="section">
<view class="section-title">、您的权利</view> <view class="section-title">、您的权利</view>
<view class="section-content"> <view class="section-content">
您对自己的个人信息享有以下权利:\n 1.查询与更正:通过小程序设置或联系客服查询、修改个人信息。
1. 访问和更新您的个人信息\n </view>
2. 删除您的个人信息\n <view class="section-content">
3. 撤回授权同意\n 2.删除信息:可删除已上传的素材或申请注销账号(需验证身份)。
4. 注销账号 </view>
<view class="section-content">
3.撤回同意:通过设置关闭非必要权限(可能影响部分功能使用)。
</view>
<view class="section-content">
4.投诉举报:对个人信息处理有异议,可通过【客服邮箱/电话】联系我们。
</view> </view>
</view> </view>
<view class="section"> <view class="section">
<view class="section-title">六、Cookie使用</view> <view class="section-title">五、未成年人保护</view>
<view class="section-content"> <view class="section-content">
我们可能使用Cookie和类似技术来改善用户体验。您可以通过浏览器设置拒绝Cookie但这可能影响某些功能的使用 1.未满14周岁用户需在监护人同意下使用服务
</view>
<view class="section-content">
2.若发现未经监护人同意的未成年人信息,将采取措施删除并终止服务。
</view> </view>
</view> </view>
<view class="section"> <view class="section">
<view class="section-title">七、未成年人保护</view> <view class="section-title">六、政策更新</view>
<view class="section-content"> <view class="section-content">
我们重视未成年人的个人信息保护。如果您是未成年人,请在监护人的陪同下阅读本政策,并在监护人同意后使用我们的服务 1.我们可能根据业务或法律要求更新本政策,并通过公告、推送通知等方式告知
</view>
<view class="section-content">
2.若您继续使用服务,视为接受更新后的政策。
</view> </view>
</view> </view>
<view class="section"> <view class="section">
<view class="section-title">八、政策更新</view> <view class="section-content" style="text-align: center; margin-top: 60rpx;">
<view class="section-content"> 【万花筒】运营团队
我们可能会不时更新本隐私政策。更新后的政策将在平台上公布,请您定期查看。
</view> </view>
<view class="section-content" style="text-align: center;">
更新日期2026年1月9日
</view> </view>
<view class="section">
<view class="section-title">九、联系我们</view>
<view class="section-content">
如您对本隐私政策有任何疑问,请通过以下方式联系我们:\n
客服邮箱privacy@example.com\n
客服电话400-888-8888
</view> </view>
</view> </view>
</scroll-view> </scroll-view>

View File

@@ -5,7 +5,7 @@ page {
} }
.agreement-container { .agreement-container {
height: 100vh; height: 100%;
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -15,7 +15,11 @@ page {
.content-scroll { .content-scroll {
flex: 1; flex: 1;
width: 100%; width: 100%;
padding: 30rpx 40rpx 60rpx; box-sizing: border-box;
}
.agreement-content {
padding: 30rpx 40rpx 120rpx;
box-sizing: border-box; box-sizing: border-box;
} }
@@ -51,3 +55,8 @@ page {
line-height: 1.8; line-height: 1.8;
white-space: pre-line; white-space: pre-line;
} }
.content-bold {
font-weight: 600;
color: #333;
}

View File

@@ -1,5 +1,5 @@
{ {
"navigationBarTitleText": "用户协议", "navigationBarTitleText": "用户协议",
"navigationBarBackgroundColor": "#ff2442", "navigationBarBackgroundColor": "#ffffff",
"navigationBarTextStyle": "white" "navigationBarTextStyle": "black"
} }

View File

@@ -1,70 +1,106 @@
<!--pages/agreement/user-agreement/user-agreement.wxml--> <!--pages/agreement/user-agreement/user-agreement.wxml-->
<view class="agreement-container"> <view class="agreement-container">
<scroll-view class="content-scroll" scroll-y> <scroll-view class="content-scroll" scroll-y="{{true}}" show-scrollbar="{{false}}" enhanced="{{true}}">
<view class="agreement-title">用户协议</view> <view class="agreement-content">
<view class="update-time">更新时间2024年12月5日</view> <view class="agreement-title">万花筒用户协议</view>
<view class="update-time">更新日期2026年1月9日</view>
<view class="update-time">生效日期2026年1月9日</view>
<view class="section"> <view class="section">
<view class="section-title">一、协议的接受</view>
<view class="section-content"> <view class="section-content">
欢迎使用AI文章审核平台。本协议是您与本平台之间关于使用本平台服务所订立的协议。请您仔细阅读本协议您使用本平台服务即表示您已阅读并同意本协议的全部内容 欢迎您使用【万花筒】请仔细阅读本协议,确认同意后方可使用服务
</view> </view>
</view> </view>
<view class="section"> <view class="section">
<view class="section-title">、服务说明</view> <view class="section-title">、服务内容</view>
<view class="section-content"> <view class="section-content">
本平台为用户提供AI文章生成、审核和管理服务。我们致力于为用户提供高效、便捷的内容管理工具 1.本小程序提供基于人工智能技术的内容生成服务,用户可领取已生成内容,或通过提交选题生成内容
</view>
<view class="section-content">
2.服务可能涉及功能调整或更新,具体以实际提供为准。
</view> </view>
</view> </view>
<view class="section"> <view class="section">
<view class="section-title">、用户账号</view> <view class="section-title">、用户义务</view>
<view class="section-content"> <view class="section-content">
1. 您需要通过微信授权登录使用本平台服务。\n 1.实名认证:部分功能需实名认证,请确保提供的信息真实有效。
2. 您应妥善保管您的账号信息,对账号下的所有活动负责。\n </view>
3. 如发现账号被盗用,请及时联系我们。 <view class="section-content">
2.合法使用:不得利用本服务从事违法或侵犯他人权益的行为(如传播虚假信息、侵害肖像权/知识产权等)。
</view>
<view class="section-content">
3.内容责任:您需保证生成的内容不违反法律法规,且已获得相关授权(如使用他人肖像需获本人同意)。
</view>
<view class="section-content">
4.账号安全:妈善保管账号信息,未经授权使用或账号被盗导致的损失由用户自行承担。
</view> </view>
</view> </view>
<view class="section"> <view class="section">
<view class="section-title">四、用户行为规范</view> <view class="section-title">三、知识产权</view>
<view class="section-content"> <view class="section-content">
您在使用本平台服务时应遵守相关法律法规,不得利用本平台从事违法违规活动,包括但不限于:\n 1.平台权利:小程序提供的技术、界面、标识等知识产权归平台所有。
1. 发布违法违规内容\n </view>
2. 侵犯他人知识产权\n <view class="section-content">
3. 传播虚假信息\n 2.侵权处理:若发现内容侵权,请联系我们并提供证明材料,平台将依法处理。
4. 其他危害平台安全的行为
</view> </view>
</view> </view>
<view class="section"> <view class="section">
<view class="section-title">五、知识产权</view> <view class="section-title">四、隐私保护</view>
<view class="section-content"> <view class="section-content">
本平台的所有内容,包括但不限于文字、图片、软件、程序等,均受著作权法等法律法规保护。未经授权,不得擅自使用 1.我们将依法收集必要信息(如账号信息、上传素材等),详细规则见《隐私政策》
</view>
<view class="section-content">
2.未经用户同意,不会向第三方披露个人信息,法律法规或监管要求除外。
</view>
<view class="section-content">
3.采用加密等技术保护数据安全,但无法保证绝对安全,用户需知悉相关风险。
</view> </view>
</view> </view>
<view class="section"> <view class="section">
<view class="section-title">、免责声明</view> <view class="section-title">、免责声明</view>
<view class="section-content"> <view class="section-content">
本平台对因不可抗力或不可归责于本平台的原因导致的服务中断或其他缺陷不承担责任。用户理解并同意自行承担使用本平台服务的风险。 1.因不可抗力(如网络故障、自然灾害等)导致的服务中断,平台不承担赔偿责任。
</view>
<view class="section-content">
2.用户不当使用或违反本协议导致的纠纷,由用户自行承担责任。
</view>
<view class="section-content">
3.生成内容仅供个人/合法用途参考,平台不对其准确性、适用性作担保。
</view> </view>
</view> </view>
<view class="section"> <view class="section">
<view class="section-title">、协议修改</view> <view class="section-title">、协议变更与终止</view>
<view class="section-content"> <view class="section-content">
我们有权根据需要修改本协议,修改后的协议将在平台上公布。您继续使用本平台服务即表示同意修改后的协议 1.平台有权修订本协议,并通过公告、推送等方式通知,若继续使用视为接受新条款
</view>
<view class="section-content">
2.用户可随时停止使用服务;若您严重违反协议,平台有权终止服务并追究责任。
</view> </view>
</view> </view>
<view class="section"> <view class="section">
<view class="section-title">八、联系我们</view> <view class="section-title">七、其他条款</view>
<view class="section-content"> <view class="section-content">
如您对本协议有任何疑问,请通过以下方式联系我们:\n 1.本协议适用中华人民共和国法律,争议提交【平台所在地】有管辖权的法院诉讼解决。
客服邮箱support@example.com\n </view>
客服电话400-888-8888 <view class="section-content">
2.本协议条款部分无效不影响其余条款效力。
</view>
</view>
<view class="section">
<view class="section-content" style="text-align: center; margin-top: 60rpx;">
【万花筒】运营团队
</view>
<view class="section-content" style="text-align: center;">
更新日期2026年1月9日
</view>
</view> </view>
</view> </view>
</scroll-view> </scroll-view>

View File

@@ -5,7 +5,7 @@ page {
} }
.agreement-container { .agreement-container {
height: 100vh; height: 100%;
width: 100%; width: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -15,7 +15,11 @@ page {
.content-scroll { .content-scroll {
flex: 1; flex: 1;
width: 100%; width: 100%;
padding: 30rpx 40rpx 60rpx; box-sizing: border-box;
}
.agreement-content {
padding: 30rpx 40rpx 120rpx;
box-sizing: border-box; box-sizing: border-box;
} }

View File

@@ -53,7 +53,7 @@ Page({
success: (res) => { success: (res) => {
if (res.confirm) { if (res.confirm) {
wx.redirectTo({ wx.redirectTo({
url: '/pages/profile/social-binding/social-binding' url: '/pages/profile/platform-bind/platform-bind'
}); });
} else { } else {
wx.navigateBack(); wx.navigateBack();

View File

@@ -236,7 +236,7 @@ Page({
success: (res) => { success: (res) => {
if (res.confirm) { if (res.confirm) {
wx.navigateTo({ wx.navigateTo({
url: '/pages/profile/social-binding/social-binding' url: '/pages/profile/platform-bind/platform-bind'
}); });
} }
} }

View File

@@ -63,7 +63,4 @@
</checkbox-group> </checkbox-group>
</view> </view>
</view> </view>
<!-- 底部指示器 -->
<view class="bottom-indicator"></view>
</view> </view>

View File

@@ -2,17 +2,17 @@
page { page {
height: 100vh; height: 100vh;
background: #ffffff; background: #ffffff;
overflow: hidden;
} }
.container { .container {
width: 100%; width: 100%;
margin: 0 auto; height: 100vh;
background-color: #fff; background-color: #fff;
min-height: 100vh;
position: relative; position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding-bottom: 40rpx; overflow: hidden;
} }
.login-content { .login-content {
@@ -133,13 +133,13 @@ page {
.agreement-section { .agreement-section {
margin-top: 32rpx; margin-top: 32rpx;
width: 100%; width: 100%;
padding-left: 40rpx; padding: 0 40rpx;
box-sizing: border-box;
} }
.agreement-label { .agreement-label {
display: flex; display: flex;
align-items: center; align-items: flex-start;
justify-content: center;
gap: 12rpx; gap: 12rpx;
} }
@@ -179,6 +179,8 @@ checkbox .wx-checkbox-input-checked::before {
font-size: 24rpx; font-size: 24rpx;
line-height: 1.6; line-height: 1.6;
color: #999; color: #999;
word-wrap: break-word;
word-break: break-all;
} }
.normal-text { .normal-text {
@@ -189,14 +191,3 @@ checkbox .wx-checkbox-input-checked::before {
color: #07c160; color: #07c160;
font-weight: 500; font-weight: 500;
} }
.bottom-indicator {
position: absolute;
bottom: 16rpx;
left: 50%;
transform: translateX(-50%);
width: 268rpx;
height: 10rpx;
background: #000;
border-radius: 6rpx;
}

View File

@@ -15,7 +15,11 @@ Page({
countryCodes: ['+86', '+852', '+853', '+886', '+1', '+44', '+81', '+82'], countryCodes: ['+86', '+852', '+853', '+886', '+1', '+44', '+81', '+82'],
countryCodeIndex: 0, countryCodeIndex: 0,
pollTimer: null as any, // 轮询定时器 pollTimer: null as any, // 轮询定时器
pollCount: 0 // 轮询次数 pollCount: 0, // 轮询次数
// 验证码相关
needCaptcha: false, // 是否需要验证码
captchaType: '', // 验证码类型
qrcodeImage: '' // 二维码图片base64
}, },
onLoad() { onLoad() {
@@ -305,6 +309,20 @@ Page({
}); });
}, 2000); }, 2000);
} else if (status.status === 'need_captcha') {
// 需要验证码验证
this.stopPolling();
console.log('需要验证码验证:', status.captcha_type);
this.setData({
showLoading: false,
needCaptcha: true,
captchaType: status.captcha_type || 'unknown',
qrcodeImage: status.qrcode_image || '',
loadingText: status.message || '需要验证码验证'
});
} else if (status.status === 'processing') { } else if (status.status === 'processing') {
// 仍在处理中,继续轮询 // 仍在处理中,继续轮询
this.setData({ this.setData({

View File

@@ -12,7 +12,14 @@
<text class="page-title">请绑定小红书账号</text> <text class="page-title">请绑定小红书账号</text>
<text class="page-subtitle">手机号未注册小红书会导致绑定失败</text> <text class="page-subtitle">手机号未注册小红书会导致绑定失败</text>
<view class="bind-form"> <!-- 二维码验证区域 -->
<view class="qrcode-section" wx:if="{{needCaptcha && qrcodeImage}}">
<text class="qrcode-title">请使用小红书APP扫描二维码</text>
<image class="qrcode" src="{{qrcodeImage}}" mode="aspectFit"></image>
<text class="qrcode-hint">扫码后即可继续绑定流程</text>
</view>
<view class="bind-form" wx:if="{{!needCaptcha}}">
<view class="input-row"> <view class="input-row">
<text class="label">手机号</text> <text class="label">手机号</text>
<picker mode="selector" range="{{countryCodes}}" value="{{countryCodeIndex}}" bindchange="onCountryCodeChange"> <picker mode="selector" range="{{countryCodes}}" value="{{countryCodeIndex}}" bindchange="onCountryCodeChange">

View File

@@ -56,6 +56,42 @@ page {
display: block; display: block;
} }
/* 二维码验证区域 */
.qrcode-section {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
padding: 48rpx 0;
margin-bottom: 48rpx;
}
.qrcode-title {
font-size: 32rpx;
font-weight: 500;
color: #333;
margin-bottom: 48rpx;
text-align: center;
}
.qrcode {
width: 500rpx;
height: 500rpx;
border: 2rpx solid #E5E5E5;
border-radius: 16rpx;
padding: 32rpx;
background: #fff;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
margin-bottom: 32rpx;
}
.qrcode-hint {
font-size: 26rpx;
color: #999;
text-align: center;
line-height: 1.6;
}
.bind-form { .bind-form {
width: 100%; width: 100%;
} }

View File

@@ -373,7 +373,7 @@ Page({
// 社交账号绑定 // 社交账号绑定
goToSocialBinding() { goToSocialBinding() {
wx.navigateTo({ wx.navigateTo({
url: '/pages/profile/social-binding/social-binding' url: '/pages/profile/platform-bind/platform-bind'
}); });
}, },

View File

@@ -110,7 +110,7 @@ Page({
// Cookie失效直接跳转重新绑定 // Cookie失效直接跳转重新绑定
if (this.data.xiaohongshuCookieExpired) { if (this.data.xiaohongshuCookieExpired) {
wx.navigateTo({ wx.navigateTo({
url: '/pages/profile/xhs-login/xhs-login' url: '/pages/profile/platform-bind/platform-bind'
}); });
return; return;
} }
@@ -123,7 +123,7 @@ Page({
// 未绑定,跳转到绑定页 // 未绑定,跳转到绑定页
wx.navigateTo({ wx.navigateTo({
url: '/pages/profile/xhs-login/xhs-login' url: '/pages/profile/platform-bind/platform-bind'
}); });
return; return;
} }

View File

@@ -105,6 +105,8 @@ export class EmployeeService {
message?: string; message?: string;
xhs_account?: string; xhs_account?: string;
error?: string; error?: string;
captcha_type?: string; // 验证码类型
qrcode_image?: string; // 二维码图片base64
}>(API.employee.bindXHSStatus); }>(API.employee.bindXHSStatus);
} }