commit
This commit is contained in:
@@ -1,24 +1,15 @@
|
||||
{
|
||||
"pages": [
|
||||
"pages/home/home",
|
||||
"pages/article-generate/article-generate",
|
||||
"pages/login/login",
|
||||
"pages/login/phone-login",
|
||||
"pages/articles/articles",
|
||||
"pages/article-detail/article-detail",
|
||||
"pages/profile/profile",
|
||||
"pages/profile/user-info/user-info",
|
||||
"pages/profile/social-binding/social-binding",
|
||||
"pages/profile/platform-bind/platform-bind",
|
||||
"pages/profile/xhs-login/xhs-login",
|
||||
"pages/profile/published/published",
|
||||
"pages/profile/article-detail/article-detail",
|
||||
"pages/profile/about/about",
|
||||
"pages/profile/feedback/feedback",
|
||||
"pages/agreement/user-agreement/user-agreement",
|
||||
"pages/agreement/privacy-policy/privacy-policy",
|
||||
"pages/index/index",
|
||||
"pages/logs/logs"
|
||||
"pages/agreement/privacy-policy/privacy-policy"
|
||||
],
|
||||
"window": {
|
||||
"navigationBarTextStyle": "white",
|
||||
|
||||
@@ -56,14 +56,6 @@ Page({
|
||||
this.setData({
|
||||
showClaimButton: false
|
||||
});
|
||||
|
||||
// 延迟后跳转到发布页面,传递领取信息
|
||||
setTimeout(() => {
|
||||
const copy = response.data!.copy;
|
||||
wx.redirectTo({
|
||||
url: `/pages/article-generate/article-generate?copyId=${copyId}&claimId=${response.data!.claim_id}&productId=${productId}&productName=${encodeURIComponent(copy.title)}&title=${encodeURIComponent(copy.title)}&content=${encodeURIComponent(copy.content)}`
|
||||
});
|
||||
}, 1500);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('领取文案失败:', error);
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"usingComponents": {
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// index.ts
|
||||
// 获取应用实例
|
||||
const app = getApp<IAppOption>()
|
||||
const defaultAvatarUrl = 'https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0'
|
||||
|
||||
Component({
|
||||
data: {
|
||||
motto: 'Hello World',
|
||||
userInfo: {
|
||||
avatarUrl: defaultAvatarUrl,
|
||||
nickName: '',
|
||||
},
|
||||
hasUserInfo: false,
|
||||
canIUseGetUserProfile: wx.canIUse('getUserProfile'),
|
||||
canIUseNicknameComp: wx.canIUse('input.type.nickname'),
|
||||
},
|
||||
methods: {
|
||||
// 事件处理函数
|
||||
bindViewTap() {
|
||||
wx.navigateTo({
|
||||
url: '../logs/logs',
|
||||
})
|
||||
},
|
||||
onChooseAvatar(e: any) {
|
||||
const { avatarUrl } = e.detail
|
||||
const { nickName } = this.data.userInfo
|
||||
this.setData({
|
||||
"userInfo.avatarUrl": avatarUrl,
|
||||
hasUserInfo: nickName && avatarUrl && avatarUrl !== defaultAvatarUrl,
|
||||
})
|
||||
},
|
||||
onInputChange(e: any) {
|
||||
const nickName = e.detail.value
|
||||
const { avatarUrl } = this.data.userInfo
|
||||
this.setData({
|
||||
"userInfo.nickName": nickName,
|
||||
hasUserInfo: nickName && avatarUrl && avatarUrl !== defaultAvatarUrl,
|
||||
})
|
||||
},
|
||||
getUserProfile() {
|
||||
// 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认,开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
|
||||
wx.getUserProfile({
|
||||
desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
|
||||
success: (res) => {
|
||||
console.log(res)
|
||||
this.setData({
|
||||
userInfo: res.userInfo,
|
||||
hasUserInfo: true
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
@@ -1,27 +0,0 @@
|
||||
<!--index.wxml-->
|
||||
<scroll-view class="scrollarea" scroll-y type="list">
|
||||
<view class="container">
|
||||
<view class="userinfo">
|
||||
<block wx:if="{{canIUseNicknameComp && !hasUserInfo}}">
|
||||
<button class="avatar-wrapper" open-type="chooseAvatar" bind:chooseavatar="onChooseAvatar">
|
||||
<image class="avatar" src="{{userInfo.avatarUrl}}"></image>
|
||||
</button>
|
||||
<view class="nickname-wrapper">
|
||||
<text class="nickname-label">昵称</text>
|
||||
<input type="nickname" class="nickname-input" placeholder="请输入昵称" bind:change="onInputChange" />
|
||||
</view>
|
||||
</block>
|
||||
<block wx:elif="{{!hasUserInfo}}">
|
||||
<button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 获取头像昵称 </button>
|
||||
<view wx:else> 请使用2.10.4及以上版本基础库 </view>
|
||||
</block>
|
||||
<block wx:else>
|
||||
<image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
|
||||
<text class="userinfo-nickname">{{userInfo.nickName}}</text>
|
||||
</block>
|
||||
</view>
|
||||
<view class="usermotto">
|
||||
<text class="user-motto">{{motto}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
@@ -1,62 +0,0 @@
|
||||
/**index.wxss**/
|
||||
page {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
.scrollarea {
|
||||
flex: 1;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.userinfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: #aaa;
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.userinfo-avatar {
|
||||
overflow: hidden;
|
||||
width: 128rpx;
|
||||
height: 128rpx;
|
||||
margin: 20rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.usermotto {
|
||||
margin-top: 200px;
|
||||
}
|
||||
|
||||
.avatar-wrapper {
|
||||
padding: 0;
|
||||
width: 56px !important;
|
||||
border-radius: 8px;
|
||||
margin-top: 40px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
display: block;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
}
|
||||
|
||||
.nickname-wrapper {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 16px;
|
||||
box-sizing: border-box;
|
||||
border-top: .5px solid rgba(0, 0, 0, 0.1);
|
||||
border-bottom: .5px solid rgba(0, 0, 0, 0.1);
|
||||
color: black;
|
||||
}
|
||||
|
||||
.nickname-label {
|
||||
width: 105px;
|
||||
}
|
||||
|
||||
.nickname-input {
|
||||
flex: 1;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
// pages/login/phone-login.ts
|
||||
import { API } from '../../config/api';
|
||||
import { EmployeeService } from '../../services/employee';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
@@ -143,7 +144,7 @@ Page({
|
||||
},
|
||||
|
||||
// 获取验证码
|
||||
getVerifyCode() {
|
||||
async getVerifyCode() {
|
||||
if (!this.data.agreed) {
|
||||
wx.showToast({
|
||||
title: '请先同意用户协议',
|
||||
@@ -167,56 +168,42 @@ Page({
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示加载提示
|
||||
wx.showLoading({
|
||||
title: '发送中...',
|
||||
mask: true
|
||||
});
|
||||
|
||||
// 调用后端API发送验证码
|
||||
wx.request({
|
||||
url: `${API.baseURL}/api/xhs/send-verification-code`,
|
||||
method: 'POST',
|
||||
data: {
|
||||
phone: phone
|
||||
},
|
||||
success: (res: any) => {
|
||||
wx.hideLoading();
|
||||
|
||||
if (res.statusCode === 200 && res.data.code === 200) {
|
||||
// 发送成功
|
||||
wx.showToast({
|
||||
title: '验证码已发送',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
});
|
||||
|
||||
// 开发环境打印验证码
|
||||
if (res.data.data && res.data.data.code) {
|
||||
console.log('验证码:', res.data.data.code);
|
||||
}
|
||||
|
||||
// 开始倒计时
|
||||
this.startCountdown();
|
||||
} else {
|
||||
// 发送失败
|
||||
wx.showToast({
|
||||
title: res.data.message || '发送失败,请稍后重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
},
|
||||
fail: (err) => {
|
||||
wx.hideLoading();
|
||||
console.error('发送验证码请求失败:', err);
|
||||
try {
|
||||
// 调用封装的Service方法发送验证码(禁用loading,验证码发送应立即响应)
|
||||
const res = await EmployeeService.sendXHSCode(phone, false);
|
||||
|
||||
// 兼容 code=0 和 code=200
|
||||
if (res.code === 200 || res.code === 0) {
|
||||
// 发送成功
|
||||
wx.showToast({
|
||||
title: '网络错误,请稍后重试',
|
||||
title: '验证码已发送',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
});
|
||||
|
||||
// 开发环境打印验证码
|
||||
if (res.data && res.data.code) {
|
||||
console.log('验证码:', res.data.code);
|
||||
}
|
||||
|
||||
// 开始倒计时
|
||||
this.startCountdown();
|
||||
} else {
|
||||
// 发送失败
|
||||
wx.showToast({
|
||||
title: res.message || '发送失败,请稍后重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('发送验证码失败:', err);
|
||||
wx.showToast({
|
||||
title: '网络错误,请稍后重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 开始倒计时
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"navigationBarTitleText": "关于我们",
|
||||
"navigationBarBackgroundColor": "#ff2442",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// pages/profile/about/about.ts
|
||||
Page({
|
||||
data: {
|
||||
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
|
||||
}
|
||||
});
|
||||
@@ -1,45 +0,0 @@
|
||||
<!--pages/profile/about/about.wxml-->
|
||||
<view class="page-container">
|
||||
<view class="logo-section">
|
||||
<image class="app-logo" src="/images/logo.png" mode="aspectFit"></image>
|
||||
<text class="app-name">AI文章审核平台</text>
|
||||
<text class="app-version">v1.0.0</text>
|
||||
</view>
|
||||
|
||||
<view class="info-section">
|
||||
<view class="info-card">
|
||||
<view class="card-title">产品介绍</view>
|
||||
<text class="card-content">AI文章审核平台是一款智能内容生成与审核管理系统,通过AI技术帮助用户高效管理文章内容,提升内容审核效率。</text>
|
||||
</view>
|
||||
|
||||
<view class="info-card">
|
||||
<view class="card-title">联系我们</view>
|
||||
<view class="contact-item">
|
||||
<text class="contact-label">客服邮箱:</text>
|
||||
<text class="contact-value">support@example.com</text>
|
||||
</view>
|
||||
<view class="contact-item">
|
||||
<text class="contact-label">客服电话:</text>
|
||||
<text class="contact-value">400-888-8888</text>
|
||||
</view>
|
||||
<view class="contact-item">
|
||||
<text class="contact-label">工作时间:</text>
|
||||
<text class="contact-value">周一至周五 9:00-18:00</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="info-card">
|
||||
<view class="card-title">更新日志</view>
|
||||
<view class="log-item">
|
||||
<text class="log-version">v1.0.0</text>
|
||||
<text class="log-date">2024-12-05</text>
|
||||
<text class="log-content">· 初始版本发布\n· 支持文章管理和审核\n· 优化用户体验</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="footer-section">
|
||||
<text class="copyright">© 2024 AI文章审核平台</text>
|
||||
<text class="copyright">All Rights Reserved</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -1,144 +0,0 @@
|
||||
/* pages/profile/about/about.wxss */
|
||||
page {
|
||||
background: #f8f8f8;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
min-height: 100vh;
|
||||
width: 100%;
|
||||
padding-bottom: 60rpx;
|
||||
box-sizing: border-box;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.logo-section {
|
||||
width: 100%;
|
||||
background: #07c160;
|
||||
padding: 80rpx 30rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.app-logo {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 24rpx;
|
||||
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.15);
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.app-name {
|
||||
font-size: 40rpx;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.app-version {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
.info-section {
|
||||
width: 100%;
|
||||
padding: 20rpx 30rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.info-card {
|
||||
width: 100%;
|
||||
background: white;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.06);
|
||||
box-sizing: border-box;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
padding-bottom: 16rpx;
|
||||
border-bottom: 2rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 1.8;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.contact-item {
|
||||
display: flex;
|
||||
margin-bottom: 16rpx;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.contact-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.contact-label {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
min-width: 140rpx;
|
||||
}
|
||||
|
||||
.contact-value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.log-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.log-version {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #07c160;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.log-date {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.log-content {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 1.8;
|
||||
white-space: pre-line;
|
||||
}
|
||||
|
||||
.footer-section {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 40rpx 30rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.copyright {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
line-height: 1.6;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"navigationBarTitleText": "环境切换",
|
||||
"navigationBarBackgroundColor": "#667eea",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
<!--pages/profile/env-switch/env-switch.wxml-->
|
||||
<view class="container">
|
||||
<!-- 当前环境 -->
|
||||
<view class="current-env">
|
||||
<view class="env-label">当前环境</view>
|
||||
<view class="env-value">
|
||||
<text class="env-tag env-tag-{{currentEnv}}">{{currentEnv === 'dev' ? '开发环境' : currentEnv === 'test' ? '测试环境' : '生产环境'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 环境列表 -->
|
||||
<view class="env-list">
|
||||
<view
|
||||
class="env-item {{currentEnv === item.key ? 'active' : ''}}"
|
||||
wx:for="{{envList}}"
|
||||
wx:key="key"
|
||||
bindtap="switchEnvironment"
|
||||
data-env="{{item.key}}"
|
||||
>
|
||||
<view class="env-header">
|
||||
<view class="env-name">
|
||||
<text class="env-icon" style="background-color: {{item.color}}"></text>
|
||||
<text>{{item.name}}</text>
|
||||
</view>
|
||||
<view class="env-status">
|
||||
<text wx:if="{{currentEnv === item.key}}" class="current-tag">当前</text>
|
||||
<text wx:else class="switch-text">切换</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="env-info">
|
||||
<view class="info-item">
|
||||
<text class="info-label">主服务:</text>
|
||||
<text class="info-value" bindtap="copyURL" catchtap="copyURL" data-url="{{configs[item.key].baseURL}}">
|
||||
{{configs[item.key].baseURL}}
|
||||
</text>
|
||||
</view>
|
||||
<view class="info-item" wx:if="{{configs[item.key].pythonURL}}">
|
||||
<text class="info-label">Python:</text>
|
||||
<text class="info-value" bindtap="copyURL" catchtap="copyURL" data-url="{{configs[item.key].pythonURL}}">
|
||||
{{configs[item.key].pythonURL}}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 说明 -->
|
||||
<view class="tips">
|
||||
<view class="tips-title">⚠️ 温馨提示</view>
|
||||
<view class="tips-item">• 切换环境后会清除登录状态,需要重新登录</view>
|
||||
<view class="tips-item">• 开发环境用于本地开发调试</view>
|
||||
<view class="tips-item">• 测试环境用于服务器功能测试</view>
|
||||
<view class="tips-item">• 生产环境为正式线上环境</view>
|
||||
<view class="tips-item">• 点击地址可以复制</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="actions">
|
||||
<button class="action-btn" bindtap="restartApp">重启小程序</button>
|
||||
</view>
|
||||
</view>
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"navigationBarTitleText": "意见反馈",
|
||||
"navigationBarBackgroundColor": "#07c160",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
// pages/profile/feedback/feedback.ts
|
||||
import { request } from '../../../utils/request';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
typeList: ['功能建议', 'Bug反馈', '体验问题', '其他'],
|
||||
typeIndex: 0,
|
||||
content: '',
|
||||
contact: '',
|
||||
nickname: ''
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
// 获取用户信息
|
||||
const employeeInfo = wx.getStorageSync('employeeInfo');
|
||||
if (employeeInfo && employeeInfo.name) {
|
||||
this.setData({
|
||||
nickname: employeeInfo.name
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onTypeChange(e: any) {
|
||||
this.setData({
|
||||
typeIndex: e.detail.value
|
||||
});
|
||||
},
|
||||
|
||||
onContentInput(e: any) {
|
||||
console.log('输入内容:', e.detail.value);
|
||||
this.setData({
|
||||
content: e.detail.value
|
||||
});
|
||||
},
|
||||
|
||||
onContactInput(e: any) {
|
||||
this.setData({
|
||||
contact: e.detail.value
|
||||
});
|
||||
},
|
||||
|
||||
async handleSubmit() {
|
||||
console.log('提交时的内容:', this.data.content);
|
||||
console.log('内容长度:', this.data.content.length);
|
||||
console.log('去空格后:', this.data.content.trim());
|
||||
|
||||
if (!this.data.content.trim()) {
|
||||
wx.showToast({
|
||||
title: '请输入问题描述',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
wx.showLoading({
|
||||
title: '提交中...',
|
||||
mask: true
|
||||
});
|
||||
|
||||
try {
|
||||
const res = await request({
|
||||
url: '/api/employee/feedback',
|
||||
method: 'POST',
|
||||
data: {
|
||||
feedback_type: this.data.typeList[this.data.typeIndex],
|
||||
description: this.data.content.trim(),
|
||||
contact_info: this.data.contact.trim(),
|
||||
nickname: this.data.nickname
|
||||
}
|
||||
});
|
||||
|
||||
wx.hideLoading();
|
||||
|
||||
if (res.code === 200) {
|
||||
wx.showToast({
|
||||
title: '提交成功',
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
wx.navigateBack();
|
||||
}, 1500);
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: res.message || '提交失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
} catch (error: any) {
|
||||
wx.hideLoading();
|
||||
wx.showToast({
|
||||
title: error.message || '网络错误',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,38 +0,0 @@
|
||||
<!--pages/profile/feedback/feedback.wxml-->
|
||||
<view class="page-container">
|
||||
<view class="form-section">
|
||||
<view class="form-item">
|
||||
<view class="item-label">反馈类型</view>
|
||||
<picker bindchange="onTypeChange" value="{{typeIndex}}" range="{{typeList}}">
|
||||
<view class="picker-value">
|
||||
{{typeList[typeIndex]}}
|
||||
<text class="picker-arrow">›</text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="form-item textarea-item">
|
||||
<view class="item-label">问题描述</view>
|
||||
<textarea
|
||||
class="feedback-textarea"
|
||||
placeholder="请详细描述您遇到的问题或建议"
|
||||
maxlength="500"
|
||||
model:value="{{content}}"
|
||||
/>
|
||||
<view class="char-count">{{content.length}}/500</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="item-label">联系方式(选填)</view>
|
||||
<input
|
||||
class="feedback-input"
|
||||
placeholder="请输入您的手机号或邮箱"
|
||||
model:value="{{contact}}"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="submit-section">
|
||||
<button class="submit-btn" bindtap="handleSubmit">提交反馈</button>
|
||||
</view>
|
||||
</view>
|
||||
@@ -1,102 +0,0 @@
|
||||
/* pages/profile/feedback/feedback.wxss */
|
||||
page {
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
min-height: 100vh;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
width: 100%;
|
||||
background: white;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.form-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.picker-value {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.picker-arrow {
|
||||
font-size: 36rpx;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.feedback-textarea {
|
||||
width: 100%;
|
||||
min-height: 300rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
padding: 20rpx;
|
||||
background: #f8f8f8;
|
||||
border-radius: 8rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.char-count {
|
||||
text-align: right;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-top: 12rpx;
|
||||
}
|
||||
|
||||
.feedback-input {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
line-height: 80rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
padding: 0 20rpx;
|
||||
background: #f8f8f8;
|
||||
border-radius: 8rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.submit-section {
|
||||
width: 100%;
|
||||
padding: 40rpx 30rpx;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
background: #07c160;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 50rpx;
|
||||
padding: 32rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 8rpx 24rpx rgba(7, 193, 96, 0.3);
|
||||
}
|
||||
|
||||
.submit-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.submit-btn:active {
|
||||
opacity: 0.9;
|
||||
transform: translateY(2rpx);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
// pages/profile/platform-bind/platform-bind.ts
|
||||
import { EmployeeService } from '../../../services/employee';
|
||||
import { API } from '../../../config/api';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
@@ -19,7 +20,20 @@ Page({
|
||||
// 验证码相关
|
||||
needCaptcha: false, // 是否需要验证码
|
||||
captchaType: '', // 验证码类型
|
||||
qrcodeImage: '' // 二维码图片base64
|
||||
qrcodeImage: '', // 二维码图片base64
|
||||
sessionId: '', // 发送验证码时返回的session_id,用于复用浏览器
|
||||
// 登录方式
|
||||
loginType: 'phone' as 'phone' | 'qrcode', // phone: 手机号登录, qrcode: 扫码登录
|
||||
qrcodeSessionId: '', // 扫码登录的session_id
|
||||
qrcodeExpired: false, // 二维码是否过期
|
||||
statusText: '', // 状态文本
|
||||
statusDesc: '', // 状态描述
|
||||
qrcodePolling: false, // 是否正在轮询二维码状态
|
||||
qrUrl: '', // 二维码登录链接
|
||||
qrId: '', // 二维码ID
|
||||
qrCode: '', // 二维码code
|
||||
qrcodeError: '', // 二维码加载错误提示
|
||||
qrcodeLoading: false // 二维码是否正在加载
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
@@ -83,7 +97,15 @@ Page({
|
||||
const countryCode = countryCodes[countryCodeIndex];
|
||||
console.log('发送验证码到:', phone, '区号:', countryCode);
|
||||
|
||||
await EmployeeService.sendXHSCode(phone);
|
||||
const result = await EmployeeService.sendXHSCode(phone);
|
||||
|
||||
// 保存session_id用于后续复用浏览器
|
||||
if (result.data && result.data.session_id) {
|
||||
this.setData({
|
||||
sessionId: result.data.session_id
|
||||
});
|
||||
console.log('已保存session_id:', result.data.session_id);
|
||||
}
|
||||
|
||||
this.setData({
|
||||
showLoading: false
|
||||
@@ -142,7 +164,7 @@ Page({
|
||||
|
||||
// 绑定账号
|
||||
async bindAccount() {
|
||||
const { phone, code } = this.data;
|
||||
const { phone, code, sessionId } = this.data;
|
||||
|
||||
// 验证手机号
|
||||
if (!phone || phone.length !== 11) {
|
||||
@@ -163,6 +185,16 @@ Page({
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证session_id
|
||||
if (!sessionId) {
|
||||
wx.showToast({
|
||||
title: '请重新发送验证码',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示加载
|
||||
this.setData({
|
||||
@@ -173,9 +205,9 @@ Page({
|
||||
|
||||
try {
|
||||
// 调用后端API进行绑定(异步处理)
|
||||
console.log('绑定小红书账号:', { phone, code });
|
||||
console.log('绑定小红书账号:', { phone, code, sessionId });
|
||||
|
||||
const result = await EmployeeService.bindXHS(phone, code);
|
||||
const result = await EmployeeService.bindXHS(phone, code, sessionId);
|
||||
|
||||
// 后端立即返回,开始轮询绑定状态
|
||||
this.setData({
|
||||
@@ -267,7 +299,7 @@ Page({
|
||||
showSuccess: true
|
||||
});
|
||||
|
||||
// 保存绑定信息到本地
|
||||
// 更新本地绑定状态缓存
|
||||
const bindings = wx.getStorageSync('socialBindings') || {};
|
||||
bindings.xiaohongshu = {
|
||||
phone: this.data.phone,
|
||||
@@ -276,17 +308,17 @@ Page({
|
||||
cookieExpired: false
|
||||
};
|
||||
wx.setStorageSync('socialBindings', bindings);
|
||||
|
||||
console.log('[手机号登录] 绑定成功,已更新本地缓存');
|
||||
|
||||
setTimeout(() => {
|
||||
this.setData({
|
||||
showSuccess: false
|
||||
});
|
||||
|
||||
// 绑定成功后直接跳转到首页
|
||||
wx.reLaunch({
|
||||
url: '/pages/home/home'
|
||||
});
|
||||
}, 1500);
|
||||
// 绑定成功后返回个人中心
|
||||
wx.navigateBack();
|
||||
}, 2000);
|
||||
|
||||
} else if (status.status === 'failed') {
|
||||
// 绑定失败
|
||||
@@ -344,5 +376,477 @@ Page({
|
||||
pollTimer: null
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 切换到手机号登录
|
||||
switchToPhone() {
|
||||
// 停止二维码轮询
|
||||
this.stopQRCodePolling();
|
||||
|
||||
// 清空所有扫码登录相关数据
|
||||
this.setData({
|
||||
loginType: 'phone',
|
||||
qrcodeSessionId: '',
|
||||
qrcodeImage: '',
|
||||
qrcodeExpired: false,
|
||||
qrcodeError: '',
|
||||
statusText: '',
|
||||
statusDesc: '',
|
||||
qrUrl: '',
|
||||
qrId: '',
|
||||
qrCode: '',
|
||||
// 同时清空验证码登录的数据
|
||||
phoneNumber: '',
|
||||
verificationCode: '',
|
||||
countdown: 0,
|
||||
isCounting: false
|
||||
});
|
||||
},
|
||||
|
||||
// 切换到扫码登录
|
||||
async switchToQRCode() {
|
||||
// 清空验证码登录的数据
|
||||
this.setData({
|
||||
loginType: 'qrcode',
|
||||
phoneNumber: '',
|
||||
verificationCode: '',
|
||||
countdown: 0,
|
||||
isCounting: false,
|
||||
qrcodeLoading: true,
|
||||
loadingText: '正在加载二维码...',
|
||||
qrcodeError: '' // 清空错误提示
|
||||
});
|
||||
|
||||
try {
|
||||
// 调用Go后端接口启动扫码登录
|
||||
const requestUrl = `${API.baseURL}/api/xhs/qrcode/start`;
|
||||
console.log('[扫码登录] 请求URL:', requestUrl);
|
||||
console.log('[扫码登录] 请求时间:', new Date().toISOString());
|
||||
console.log('[扫码登录] Token:', wx.getStorageSync('token') ? '已设置' : '未设置');
|
||||
|
||||
const data: any = await new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: requestUrl,
|
||||
method: 'POST',
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token')}`
|
||||
},
|
||||
success: (res) => {
|
||||
console.log('[扫码登录] 响应状态:', res.statusCode);
|
||||
console.log('[扫码登录] 响应数据:', res.data);
|
||||
resolve(res.data);
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('[扫码登录] 请求失败:', err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (data.code === 0 && data.data) {
|
||||
console.log('二维码数据:', data.data);
|
||||
|
||||
this.setData({
|
||||
qrcodeLoading: false,
|
||||
qrcodeSessionId: data.data.session_id,
|
||||
qrcodeImage: data.data.qrcode_image,
|
||||
statusText: data.data.status_text || '请使用小红书APP扫码',
|
||||
statusDesc: data.data.status_desc || '',
|
||||
qrcodeExpired: data.data.is_expired || false,
|
||||
// 保存二维码创建信息
|
||||
qrUrl: data.data.qr_url || '',
|
||||
qrId: data.data.qr_id || '',
|
||||
qrCode: data.data.qr_code || ''
|
||||
});
|
||||
|
||||
// 如果有二维码URL,打印出来
|
||||
if (data.data.qr_url) {
|
||||
console.log('='.repeat(50));
|
||||
console.log('二维码登录链接:');
|
||||
console.log(data.data.qr_url);
|
||||
console.log('二维码ID:', data.data.qr_id);
|
||||
console.log('二维码code:', data.data.qr_code);
|
||||
console.log('='.repeat(50));
|
||||
}
|
||||
|
||||
// 开始轮询二维码状态
|
||||
this.startQRCodePolling();
|
||||
} else {
|
||||
throw new Error(data.message || '获取二维码失败');
|
||||
}
|
||||
} catch (error: any) {
|
||||
// 显示错误提示在二维码区域,不跳转到手机号登录
|
||||
this.setData({
|
||||
qrcodeLoading: false,
|
||||
qrcodeError: error.message || '加载失败,请重试'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 开始轮询二维码状态
|
||||
startQRCodePolling() {
|
||||
if (this.data.qrcodePolling) {
|
||||
return; // 已经在轮询了
|
||||
}
|
||||
|
||||
this.setData({
|
||||
qrcodePolling: true
|
||||
});
|
||||
|
||||
const pollTimer = setInterval(() => {
|
||||
this.checkQRCodeStatus();
|
||||
}, 2000); // 每2秒轮询一次
|
||||
|
||||
this.setData({
|
||||
pollTimer: pollTimer
|
||||
});
|
||||
},
|
||||
|
||||
// 停止轮询二维码状态
|
||||
stopQRCodePolling() {
|
||||
if (this.data.pollTimer) {
|
||||
clearInterval(this.data.pollTimer);
|
||||
this.setData({
|
||||
pollTimer: null,
|
||||
qrcodePolling: false
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 检查二维码状态
|
||||
async checkQRCodeStatus() {
|
||||
const { qrcodeSessionId } = this.data;
|
||||
if (!qrcodeSessionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const requestUrl = `${API.baseURL}/api/xhs/qrcode/status`;
|
||||
console.log('[扫码状态] 请求URL:', requestUrl);
|
||||
console.log('[扫码状态] SessionID:', qrcodeSessionId);
|
||||
|
||||
const data: any = await new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: requestUrl,
|
||||
method: 'POST',
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token')}`
|
||||
},
|
||||
data: {
|
||||
session_id: qrcodeSessionId
|
||||
},
|
||||
success: (res) => {
|
||||
console.log('[扫码状态] 响应:', res.data);
|
||||
resolve(res.data);
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('[扫码状态] 请求失败:', err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 检查是否session失效(code=2)
|
||||
if (data.code === 2 && data.data && data.data.session_expired) {
|
||||
console.log('⚠️ 会话已失效,停止轮询并显示提示');
|
||||
|
||||
// 停止轮询
|
||||
this.stopQRCodePolling();
|
||||
|
||||
// 显示提示
|
||||
this.setData({
|
||||
qrcodeExpired: true,
|
||||
statusText: '服务已重启,请刷新二维码',
|
||||
statusDesc: '点击刷新'
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.code === 0 && data.data) {
|
||||
// 检查是否扫码登录成功
|
||||
if (data.data.login_success) {
|
||||
console.log('\u2705 \u626b\u7801\u767b\u5f55\u6210\u529f\uff01', data.data);
|
||||
|
||||
// 停止轮询
|
||||
this.stopQRCodePolling();
|
||||
|
||||
// 显示加载状态
|
||||
this.setData({
|
||||
showLoading: true,
|
||||
loadingText: '登录成功,正在保存...'
|
||||
});
|
||||
|
||||
// 保存登录信息
|
||||
await this.saveQRCodeLoginInfo(data.data);
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新二维码状态
|
||||
this.setData({
|
||||
qrcodeImage: data.data.qrcode_image,
|
||||
statusText: data.data.status_text || '',
|
||||
statusDesc: data.data.status_desc || '',
|
||||
qrcodeExpired: data.data.is_expired || false
|
||||
});
|
||||
|
||||
// 如果二维码过期,停止轮询
|
||||
if (data.data.is_expired) {
|
||||
this.stopQRCodePolling();
|
||||
this.setData({
|
||||
statusDesc: '点击刷新'
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('检查二维码状态失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 刷新二维码
|
||||
async refreshQRCode() {
|
||||
const { qrcodeSessionId } = this.data;
|
||||
if (!qrcodeSessionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setData({
|
||||
showLoading: true,
|
||||
loadingText: '正在刷新二维码...'
|
||||
});
|
||||
|
||||
try {
|
||||
const requestUrl = `${API.baseURL}/api/xhs/qrcode/refresh`;
|
||||
console.log('[刷新二维码] 请求URL:', requestUrl);
|
||||
console.log('[刷新二维码] SessionID:', qrcodeSessionId);
|
||||
|
||||
const data: any = await new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: requestUrl,
|
||||
method: 'POST',
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token')}`
|
||||
},
|
||||
data: {
|
||||
session_id: qrcodeSessionId
|
||||
},
|
||||
success: (res) => {
|
||||
console.log('[刷新二维码] 响应:', res.data);
|
||||
resolve(res.data);
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('[刷新二维码] 请求失败:', err);
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (data.code === 0 && data.data) {
|
||||
console.log('刷新二维码数据:', data.data);
|
||||
|
||||
this.setData({
|
||||
showLoading: false,
|
||||
qrcodeImage: data.data.qrcode_image,
|
||||
statusText: data.data.status_text || '请使用小红书APP扫码',
|
||||
statusDesc: data.data.status_desc || '',
|
||||
qrcodeExpired: data.data.is_expired || false,
|
||||
// 更新二维码创建信息
|
||||
qrUrl: data.data.qr_url || '',
|
||||
qrId: data.data.qr_id || '',
|
||||
qrCode: data.data.qr_code || ''
|
||||
});
|
||||
|
||||
// 如果有二维码URL,打印出来
|
||||
if (data.data.qr_url) {
|
||||
console.log('='.repeat(50));
|
||||
console.log('刷新后的二维码登录链接:');
|
||||
console.log(data.data.qr_url);
|
||||
console.log('二维码ID:', data.data.qr_id);
|
||||
console.log('二维码code:', data.data.qr_code);
|
||||
console.log('='.repeat(50));
|
||||
}
|
||||
|
||||
// 重新开始轮询
|
||||
this.stopQRCodePolling();
|
||||
this.startQRCodePolling();
|
||||
} else if (data.code === 3 && data.data && data.data.need_restart) {
|
||||
// 需要重启扫码登录
|
||||
console.log('⚠️ 页面已失效,重新启动扫码登录');
|
||||
this.setData({
|
||||
showLoading: false
|
||||
});
|
||||
|
||||
wx.showToast({
|
||||
title: '页面已失效,正在重新启动...',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
|
||||
// 停止轮询
|
||||
this.stopQRCodePolling();
|
||||
|
||||
// 等待提示显示后重新启动
|
||||
setTimeout(() => {
|
||||
this.switchToQRCode();
|
||||
}, 1000);
|
||||
} else {
|
||||
throw new Error(data.message || '刷新失败');
|
||||
}
|
||||
} catch (error: any) {
|
||||
this.setData({
|
||||
showLoading: false
|
||||
});
|
||||
|
||||
wx.showToast({
|
||||
title: error.message || '刷新失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 复制二维码链接
|
||||
copyQRUrl() {
|
||||
const { qrUrl } = this.data;
|
||||
if (!qrUrl) {
|
||||
wx.showToast({
|
||||
title: '暂无链接',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
wx.setClipboardData({
|
||||
data: qrUrl,
|
||||
success: () => {
|
||||
wx.showToast({
|
||||
title: '链接已复制',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
});
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({
|
||||
title: '复制失败',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 取消扫码登录,释放浏览器资源
|
||||
cancelQRCodeLogin(sessionId: string) {
|
||||
if (!sessionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
wx.request({
|
||||
url: `${API.baseURL}/api/xhs/qrcode/cancel`,
|
||||
method: 'POST',
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${wx.getStorageSync('token')}`
|
||||
},
|
||||
data: { session_id: sessionId },
|
||||
success: () => {
|
||||
console.log('[扫码登录] 已释放浏览器资源');
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('[扫码登录] 释放失败:', err);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 保存扫码登录信息
|
||||
async saveQRCodeLoginInfo(loginData: any) {
|
||||
try {
|
||||
console.log('开始保存扫码登录信息...', loginData);
|
||||
|
||||
// 获取用户token
|
||||
const token = wx.getStorageSync('token');
|
||||
if (!token) {
|
||||
throw new Error('未登录,请先登录');
|
||||
}
|
||||
|
||||
// 扫码登录和验证码登录不一样,需要调用Python后端保存
|
||||
// Python后端已经返回了完整的登录数据,需要调用Go后端保存到数据库
|
||||
// 但是Go后端的 /api/employee/bind-xhs 接口只支持验证码登录
|
||||
// 所以我们直接调用Python后端的 /api/xhs/save-bind-info 接口
|
||||
|
||||
const saveResult: any = await new Promise((resolve, reject) => {
|
||||
wx.request({
|
||||
url: `${API.baseURL}/api/xhs/save-qrcode-login`,
|
||||
method: 'POST',
|
||||
header: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
data: {
|
||||
employee_id: (wx.getStorageSync('employeeInfo') || {}).id,
|
||||
cookies_full: loginData.cookies_full || [],
|
||||
user_info: loginData.user_info || {},
|
||||
login_state: loginData.login_state || {}
|
||||
},
|
||||
success: (res) => resolve(res.data),
|
||||
fail: (err) => reject(err)
|
||||
});
|
||||
});
|
||||
|
||||
console.log('保存结果:', saveResult);
|
||||
|
||||
// Go后端返回 code=200, Python后端返回 code=0
|
||||
if (saveResult.code === 0 || saveResult.code === 200) {
|
||||
// 保存成功,释放浏览器资源
|
||||
this.cancelQRCodeLogin(this.data.qrcodeSessionId);
|
||||
|
||||
// 更新本地缓存
|
||||
const bindings = wx.getStorageSync('socialBindings') || {};
|
||||
const userInfo = loginData.user_info || {};
|
||||
|
||||
bindings.xiaohongshu = {
|
||||
phone: userInfo.red_id || '',
|
||||
xhs_account: userInfo.nickname || '小红书用户',
|
||||
bindTime: new Date().getTime(),
|
||||
cookieExpired: false
|
||||
};
|
||||
|
||||
wx.setStorageSync('socialBindings', bindings);
|
||||
console.log('[扫码登录] 绑定成功,已更新本地缓存', bindings.xiaohongshu);
|
||||
|
||||
// 显示成功提示
|
||||
this.setData({
|
||||
showLoading: false,
|
||||
showSuccess: true
|
||||
});
|
||||
|
||||
// 2秒后跳转回个人中心
|
||||
setTimeout(() => {
|
||||
this.setData({ showSuccess: false });
|
||||
wx.navigateBack();
|
||||
}, 2000);
|
||||
} else {
|
||||
throw new Error(saveResult.message || '保存失败');
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('保存扫码登录信息失败:', error);
|
||||
|
||||
this.setData({
|
||||
showLoading: false
|
||||
});
|
||||
|
||||
wx.showToast({
|
||||
title: error.message || '绑定失败,请重试',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
|
||||
// 停止轮询并切换回手机号登录
|
||||
this.stopQRCodePolling();
|
||||
this.switchToPhone();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -12,46 +12,104 @@
|
||||
<text class="page-title">请绑定小红书账号</text>
|
||||
<text class="page-subtitle">手机号未注册小红书会导致绑定失败</text>
|
||||
|
||||
<!-- 二维码验证区域 -->
|
||||
<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 class="login-type-tabs">
|
||||
<view class="tab {{loginType === 'phone' ? 'active' : ''}}" bindtap="switchToPhone">
|
||||
<text>手机号登录</text>
|
||||
</view>
|
||||
<view class="tab {{loginType === 'qrcode' ? 'active' : ''}}" bindtap="switchToQRCode">
|
||||
<text>扫码登录</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="bind-form" wx:if="{{!needCaptcha}}">
|
||||
<view class="input-row">
|
||||
<text class="label">手机号</text>
|
||||
<picker mode="selector" range="{{countryCodes}}" value="{{countryCodeIndex}}" bindchange="onCountryCodeChange">
|
||||
<view class="prefix">{{countryCodes[countryCodeIndex]}}</view>
|
||||
</picker>
|
||||
<input
|
||||
type="number"
|
||||
placeholder="输入手机号"
|
||||
maxlength="11"
|
||||
bindinput="onPhoneInput"
|
||||
value="{{phone}}"
|
||||
/>
|
||||
<!-- 二维码扫码登录区域 -->
|
||||
<view class="qrcode-login-section" wx:if="{{loginType === 'qrcode'}}">
|
||||
<view class="qrcode-container">
|
||||
<!-- 加载中 -->
|
||||
<view class="qrcode-loading" wx:if="{{qrcodeLoading}}">
|
||||
<view class="loading-spinner"></view>
|
||||
<text class="loading-text">{{loadingText}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 二维码图片 -->
|
||||
<image class="qrcode-img" src="{{qrcodeImage}}" mode="aspectFit" wx:if="{{qrcodeImage && !qrcodeLoading}}"></image>
|
||||
|
||||
<!-- 二维码状态覆盖层(只在过期或出错时显示) -->
|
||||
<view class="qrcode-status" wx:if="{{qrcodeExpired && !qrcodeLoading}}">
|
||||
<view class="status-content">
|
||||
<text class="status-text">{{statusText || '二维码已过期'}}</text>
|
||||
<text class="status-desc" bindtap="refreshQRCode">点击刷新</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 错误提示 -->
|
||||
<view class="qrcode-error" wx:if="{{qrcodeError && !qrcodeLoading}}">
|
||||
<view class="error-content">
|
||||
<text class="error-icon">⚠️</text>
|
||||
<text class="error-text">{{qrcodeError}}</text>
|
||||
<text class="error-retry" bindtap="switchToQRCode">点击重试</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 登录链接显示区域 -->
|
||||
<view class="qr-url-section" wx:if="{{qrUrl}}">
|
||||
<view class="url-label">登录链接(可复制到浏览器或小红书APP)</view>
|
||||
<view class="url-content">
|
||||
<text class="url-text">{{qrUrl}}</text>
|
||||
</view>
|
||||
<button class="copy-btn" bindtap="copyQRUrl">复制链接</button>
|
||||
</view>
|
||||
|
||||
<view class="qrcode-tips">
|
||||
<text class="tip-text">请使用小红书APP扫描二维码</text>
|
||||
<text class="tip-desc">扫码后即可完成绑定</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 手机号登录区域 -->
|
||||
<view class="phone-login-section" wx:if="{{loginType === 'phone'}}">
|
||||
<!-- 二维码验证区域(验证码验证时出现) -->
|
||||
<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="input-row">
|
||||
<text class="label">验证码</text>
|
||||
<input
|
||||
type="number"
|
||||
placeholder="请输入验证码"
|
||||
maxlength="6"
|
||||
bindinput="onCodeInput"
|
||||
value="{{code}}"
|
||||
/>
|
||||
<button
|
||||
class="get-code {{countdown > 0 ? 'disabled' : ''}}"
|
||||
bindtap="getVerifyCode"
|
||||
>
|
||||
{{codeButtonText}}
|
||||
</button>
|
||||
</view>
|
||||
<view class="bind-form" wx:if="{{!needCaptcha}}">
|
||||
<view class="input-row">
|
||||
<text class="label">手机号</text>
|
||||
<picker mode="selector" range="{{countryCodes}}" value="{{countryCodeIndex}}" bindchange="onCountryCodeChange">
|
||||
<view class="prefix">{{countryCodes[countryCodeIndex]}}</view>
|
||||
</picker>
|
||||
<input
|
||||
type="number"
|
||||
placeholder="输入手机号"
|
||||
maxlength="11"
|
||||
bindinput="onPhoneInput"
|
||||
value="{{phone}}"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<button class="red-btn" bindtap="bindAccount">验证并绑定</button>
|
||||
<view class="input-row">
|
||||
<text class="label">验证码</text>
|
||||
<input
|
||||
type="number"
|
||||
placeholder="请输入验证码"
|
||||
maxlength="6"
|
||||
bindinput="onCodeInput"
|
||||
value="{{code}}"
|
||||
/>
|
||||
<button
|
||||
class="get-code {{countdown > 0 ? 'disabled' : ''}}"
|
||||
bindtap="getVerifyCode"
|
||||
>
|
||||
{{codeButtonText}}
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<button class="red-btn" bindtap="bindAccount">验证并绑定</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -69,7 +127,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="toast-overlay" wx:if="{{showLoading}}">
|
||||
<view class="toast-overlay" wx:if="{{showLoading && loginType === 'phone'}}">
|
||||
<view class="toast">
|
||||
<view class="toast-loading"></view>
|
||||
<text class="toast-text">{{loadingText}}</text>
|
||||
|
||||
@@ -52,10 +52,168 @@ page {
|
||||
.page-subtitle {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
margin-bottom: 80rpx;
|
||||
margin-bottom: 48rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 登录方式切换 */
|
||||
.login-type-tabs {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
margin-bottom: 48rpx;
|
||||
border-radius: 12rpx;
|
||||
background: #F5F5F5;
|
||||
padding: 8rpx;
|
||||
}
|
||||
|
||||
.login-type-tabs .tab {
|
||||
flex: 1;
|
||||
height: 72rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 8rpx;
|
||||
font-size: 30rpx;
|
||||
color: #666;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.login-type-tabs .tab.active {
|
||||
background: #fff;
|
||||
color: #FF2442;
|
||||
font-weight: 500;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
/* 二维码扫码登录区域 */
|
||||
.qrcode-login-section {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.qrcode-container {
|
||||
width: 500rpx;
|
||||
height: 500rpx;
|
||||
position: relative;
|
||||
margin-bottom: 48rpx;
|
||||
}
|
||||
|
||||
.qrcode-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 2rpx solid #E5E5E5;
|
||||
border-radius: 16rpx;
|
||||
background: #fff;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
/* 二维码状态覆盖层 */
|
||||
.qrcode-status {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.status-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.status-desc {
|
||||
font-size: 28rpx;
|
||||
color: #FF2442;
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.qrcode-tips {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.tip-text {
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tip-desc {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 二维码URL显示区域 */
|
||||
.qr-url-section {
|
||||
width: 100%;
|
||||
margin-bottom: 32rpx;
|
||||
padding: 24rpx;
|
||||
background: #F8F8F8;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.url-label {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 16rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.url-content {
|
||||
width: 100%;
|
||||
padding: 20rpx;
|
||||
background: #fff;
|
||||
border-radius: 8rpx;
|
||||
margin-bottom: 16rpx;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.url-text {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.copy-btn {
|
||||
width: 100%;
|
||||
height: 72rpx;
|
||||
background: linear-gradient(135deg, #FF2442 0%, #FF4F6A 100%);
|
||||
border-radius: 8rpx;
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
border: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 手机号登录区域 */
|
||||
.phone-login-section {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 二维码验证区域 */
|
||||
.qrcode-section {
|
||||
width: 100%;
|
||||
@@ -274,3 +432,77 @@ page {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/* 二维码加载中 */
|
||||
.qrcode-loading {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 24rpx;
|
||||
border: 2rpx solid #E5E5E5;
|
||||
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
border: 4rpx solid #E5E5E5;
|
||||
border-top-color: #FF2442;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 二维码错误提示 */
|
||||
.qrcode-error {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2rpx solid #FFE5E5;
|
||||
box-shadow: 0 8rpx 24rpx rgba(255, 36, 66, 0.1);
|
||||
}
|
||||
|
||||
.error-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
padding: 48rpx;
|
||||
}
|
||||
|
||||
.error-icon {
|
||||
font-size: 80rpx;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.error-retry {
|
||||
font-size: 28rpx;
|
||||
color: #FF2442;
|
||||
text-decoration: underline;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
{
|
||||
"navigationBarTitleText": "已发布文章",
|
||||
"navigationBarBackgroundColor": "#07c160",
|
||||
"navigationBarTextStyle": "white",
|
||||
"enablePullDownRefresh": true,
|
||||
"backgroundColor": "#f5f5f5",
|
||||
"backgroundTextStyle": "light"
|
||||
}
|
||||
@@ -1,219 +0,0 @@
|
||||
// pages/profile/published/published.ts
|
||||
import { EmployeeService, PublishRecord as ApiPublishRecord } from '../../../services/employee';
|
||||
import { getImageUrl } from '../../../utils/util';
|
||||
|
||||
interface Article {
|
||||
id: number;
|
||||
productName: string;
|
||||
title: string;
|
||||
content: string;
|
||||
tags: string[];
|
||||
images: Array<{
|
||||
id: number;
|
||||
image_url: string;
|
||||
image_thumb_url: string;
|
||||
sort_order: number;
|
||||
keywords_name: string;
|
||||
}>;
|
||||
createTime: string;
|
||||
status: string;
|
||||
}
|
||||
|
||||
Page({
|
||||
data: {
|
||||
articles: [] as Article[],
|
||||
hasLoaded: false // 是否已加载过数据
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadArticles();
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// 仅在未加载过数据时加载
|
||||
if (!this.data.hasLoaded) {
|
||||
this.loadArticles();
|
||||
}
|
||||
},
|
||||
|
||||
// 下拉刷新
|
||||
onPullDownRefresh() {
|
||||
this.loadArticles(true);
|
||||
},
|
||||
|
||||
// 初始化模拟数据
|
||||
initMockData() {
|
||||
const existingArticles = wx.getStorageSync('myArticles') || [];
|
||||
|
||||
// 如果已经有数据,不重复初始化
|
||||
if (existingArticles.length > 0) return;
|
||||
|
||||
const mockArticles = [
|
||||
{
|
||||
id: Date.now() + 1,
|
||||
productName: '兰蔻小黑瓶精华液',
|
||||
title: '【种草分享】兰蔻小黑瓶精华液使用体验💕',
|
||||
content: '姐妹们!今天必须来跟大家分享一下我最近入手的宝藏好物——兰蔻小黑瓶精华液!\n\n✨使用感受:\n用了一段时间真的太爱了!质感超级好,完全超出我的预期。包装也非常精致,送人自用都很合适。\n\n🌟推荐理由:\n1. 品质优秀,性价比超高\n2. 使用体验一级棒\n3. 颜值在线,拿出来超有面子',
|
||||
tags: ['种草分享', '好物推荐', '必买清单', '真实测评'],
|
||||
createTime: new Date(Date.now() - 3600000 * 2).toISOString(), // 2小时前
|
||||
status: 'published'
|
||||
},
|
||||
{
|
||||
id: Date.now() + 2,
|
||||
productName: 'SK-II神仙水',
|
||||
title: '真香警告!SK-II神仙水实测分享',
|
||||
content: '集美们看过来!今天给大家带来SK-II神仙水的真实使用感受~\n\n🎯第一印象:\n收到货的那一刻就被惊艳到了!包装精美,细节满满,完全是高端货的质感。\n\n💫使用体验:\n用了几天下来,真的是越用越喜欢!质量很好,用起来特别顺手,完全就是我想要的样子!',
|
||||
tags: ['真实测评', '使用心得', '好物安利', '值得入手'],
|
||||
createTime: new Date(Date.now() - 86400000).toISOString(), // 1天前
|
||||
status: 'published'
|
||||
},
|
||||
{
|
||||
id: Date.now() + 3,
|
||||
productName: 'AirPods Pro 2',
|
||||
title: '【数码种草】AirPods Pro 2使用一周真实感受',
|
||||
content: '作为一个数码发烧友,终于入手了AirPods Pro 2!用了一周来给大家分享一下真实体验。\n\n🎵音质表现:\n音质真的提升很明显,特别是低音部分,听流行音乐和播客都非常棒!\n\n🔇降噪效果:\n降噪功能强大,地铁里基本听不到外界噪音,专注力提升100%!',
|
||||
tags: ['数码好物', '音质体验', '降噪耳机'],
|
||||
createTime: new Date(Date.now() - 172800000).toISOString(), // 2天前
|
||||
status: 'published'
|
||||
},
|
||||
{
|
||||
id: Date.now() + 4,
|
||||
productName: 'Dior烈艳蓝金口红',
|
||||
title: '【美妆必入】Dior烈艳蓝金口红999试色分享',
|
||||
content: '今天来分享我最近的心头好!Dior烈艳蓝金口红999号色,真的太美了!\n\n💄色号分析:\n999是经典的正红色,白皮黄皮都能驾驭,显白效果一级棒!\n\n✨质地感受:\n润而不油,持久度也很好,吃饭喝水后还有淡淡的颜色留存。',
|
||||
tags: ['美妆种草', '口红推荐', 'Dior蓝金'],
|
||||
createTime: new Date(Date.now() - 259200000).toISOString(), // 3天前
|
||||
status: 'published'
|
||||
},
|
||||
{
|
||||
id: Date.now() + 5,
|
||||
productName: '雅诗兰黛小棕瓶',
|
||||
content: '雅诗兰黛小棕瓶是我用过最好的精华!修复力强,用了一瓶皮肤状态明显提升。\n\n🌟产品亮点:\n含有高浓度修复精华,抗氧化效果很棒,长期使用能看到细纹改善。\n\n💡使用建议:\n建议晚上使用,配合按摩手法效果更好,第二天起来皮肤非常透亮!',
|
||||
title: '【护肤心得】雅诗兰黛小棕瓶修复精华使用报告',
|
||||
tags: ['护肤精华', '抗衰老', '修复力'],
|
||||
createTime: new Date(Date.now() - 432000000).toISOString(), // 5天前
|
||||
status: 'published'
|
||||
}
|
||||
];
|
||||
|
||||
wx.setStorageSync('myArticles', mockArticles);
|
||||
},
|
||||
|
||||
// 加载文章列表
|
||||
async loadArticles(isPullRefresh: boolean = false) {
|
||||
try {
|
||||
// 从后端API获取发布记录
|
||||
const response = await EmployeeService.getMyPublishRecords(1, 50);
|
||||
|
||||
console.log('===== 已发布文章列表响应 =====');
|
||||
console.log('response:', response);
|
||||
|
||||
if (response.code === 200 && response.data) {
|
||||
const apiArticles = response.data.list.map((record: ApiPublishRecord) => {
|
||||
console.log('处理记录:', record);
|
||||
console.log('images:', record.images);
|
||||
console.log('tags:', record.tags);
|
||||
|
||||
return {
|
||||
id: record.id,
|
||||
productName: record.product_name || '未知商品',
|
||||
title: record.title,
|
||||
content: '', // 列表页不需要显示完整内容
|
||||
tags: record.tags || [],
|
||||
images: (record.images || []).map((img: any) => ({
|
||||
...img,
|
||||
image_url: getImageUrl(img.image_url),
|
||||
image_thumb_url: getImageUrl(img.image_thumb_url || img.image_url)
|
||||
})),
|
||||
createTime: record.publish_time,
|
||||
status: 'published'
|
||||
};
|
||||
});
|
||||
|
||||
console.log('转换后的文章列表:', apiArticles);
|
||||
|
||||
this.setData({
|
||||
articles: apiArticles,
|
||||
hasLoaded: true // 标记已加载
|
||||
});
|
||||
|
||||
console.log('setData后的articles:', this.data.articles);
|
||||
|
||||
if (isPullRefresh) {
|
||||
wx.showToast({
|
||||
title: '刷新成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
});
|
||||
}
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载发布记录失败:', error);
|
||||
} finally {
|
||||
if (isPullRefresh) {
|
||||
wx.stopPullDownRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
// 如果API失败,尝试使用本地数据
|
||||
const articles = wx.getStorageSync('myArticles') || [];
|
||||
|
||||
// 格式化时间
|
||||
const formattedArticles = articles.map((item: Article) => {
|
||||
return {
|
||||
...item,
|
||||
createTime: this.formatTime(item.createTime)
|
||||
};
|
||||
});
|
||||
|
||||
this.setData({
|
||||
articles: formattedArticles,
|
||||
hasLoaded: true
|
||||
});
|
||||
|
||||
if (isPullRefresh) {
|
||||
wx.stopPullDownRefresh();
|
||||
}
|
||||
},
|
||||
|
||||
// 格式化时间
|
||||
formatTime(isoString: string): string {
|
||||
const date = new Date(isoString);
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hours = String(date.getHours()).padStart(2, '0');
|
||||
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||
|
||||
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
||||
},
|
||||
|
||||
// 查看文章详情
|
||||
viewArticle(e: any) {
|
||||
const index = e.currentTarget.dataset.index;
|
||||
const article = this.data.articles[index];
|
||||
|
||||
// 跳转到文章详情页
|
||||
wx.navigateTo({
|
||||
url: `/pages/profile/article-detail/article-detail?id=${article.id}`
|
||||
});
|
||||
},
|
||||
|
||||
// 分享功能
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '我的发布记录 - 万花筒AI助手',
|
||||
path: '/pages/home/home',
|
||||
imageUrl: ''
|
||||
};
|
||||
},
|
||||
|
||||
// 分享到朋友圈
|
||||
onShareTimeline() {
|
||||
return {
|
||||
title: '万花筒AI助手 - 智能生成种草文案',
|
||||
imageUrl: ''
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -1,56 +0,0 @@
|
||||
<!--pages/profile/published/published.wxml-->
|
||||
<view class="page-container">
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" wx:if="{{articles.length === 0}}">
|
||||
<view class="empty-icon">📝</view>
|
||||
<text class="empty-text">还没有发布任何文章</text>
|
||||
<text class="empty-hint">去首页选择商品发布种草文章吧~</text>
|
||||
</view>
|
||||
|
||||
<!-- 文章列表 -->
|
||||
<scroll-view class="article-list" scroll-y wx:else>
|
||||
<view
|
||||
class="article-item"
|
||||
wx:for="{{articles}}"
|
||||
wx:key="id"
|
||||
bindtap="viewArticle"
|
||||
data-index="{{index}}"
|
||||
>
|
||||
<view class="article-content">
|
||||
<view class="article-header">
|
||||
<text class="article-title">{{item.title}}</text>
|
||||
<text class="article-time">{{item.createTime}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 文章图片 -->
|
||||
<view class="article-images" wx:if="{{item.images && item.images.length > 0}}">
|
||||
<image
|
||||
class="article-image"
|
||||
wx:for="{{item.images}}"
|
||||
wx:key="id"
|
||||
wx:for-item="image"
|
||||
src="{{image.image_thumb_url}}"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="article-footer">
|
||||
<view class="article-product">
|
||||
<text class="product-label">商品:</text>
|
||||
<text class="product-name">{{item.productName}}</text>
|
||||
</view>
|
||||
<view class="article-tags" wx:if="{{item.tags && item.tags.length > 0}}">
|
||||
<text
|
||||
class="tag-item"
|
||||
wx:for="{{item.tags}}"
|
||||
wx:key="index"
|
||||
wx:for-item="tag"
|
||||
>
|
||||
#{{tag}}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
@@ -1,146 +0,0 @@
|
||||
/* pages/profile/published/published.wxss */
|
||||
page {
|
||||
background: #f8f8f8;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 200rpx 60rpx;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 120rpx;
|
||||
margin-bottom: 30rpx;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 32rpx;
|
||||
color: #999;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.empty-hint {
|
||||
font-size: 26rpx;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
/* 文章列表 */
|
||||
.article-list {
|
||||
flex: 1;
|
||||
padding: 20rpx;
|
||||
box-sizing: border-box;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.article-item {
|
||||
background: white;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.article-content {
|
||||
padding: 30rpx;
|
||||
}
|
||||
|
||||
.article-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.article-title {
|
||||
flex: 1;
|
||||
font-size: 32rpx;
|
||||
color: #1a1a1a;
|
||||
font-weight: bold;
|
||||
line-height: 1.4;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.article-time {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
/* 文章图片 */
|
||||
.article-images {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 12rpx;
|
||||
margin: 20rpx 0;
|
||||
}
|
||||
|
||||
.article-image {
|
||||
width: 100%;
|
||||
height: 200rpx;
|
||||
border-radius: 8rpx;
|
||||
background: #f5f5f5;
|
||||
}
|
||||
|
||||
.article-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 3;
|
||||
overflow: hidden;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.article-footer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16rpx;
|
||||
}
|
||||
|
||||
.article-product {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.product-label {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.product-name {
|
||||
font-size: 24rpx;
|
||||
color: #ff2442;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.article-tags {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 12rpx;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tag-item {
|
||||
padding: 4rpx 16rpx;
|
||||
background: linear-gradient(135deg, #fff5f7 0%, #ffe8ec 100%);
|
||||
border-radius: 16rpx;
|
||||
font-size: 22rpx;
|
||||
color: #ff2442;
|
||||
line-height: 1.5;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"navigationBarTitleText": "社交账号绑定",
|
||||
"navigationBarBackgroundColor": "#07c160",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
import { EmployeeService } from '../../../services/employee';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
// 小红书
|
||||
xiaohongshuBinded: false,
|
||||
xiaohongshuPhone: '',
|
||||
xiaohongshuAccount: '',
|
||||
xiaohongshuCookieExpired: false, // Cookie是否失效
|
||||
xiaohongshuStatusText: '去绑定',
|
||||
xiaohongshuStatusClass: '',
|
||||
|
||||
// 微博
|
||||
weiboBinded: false,
|
||||
weiboPhone: '',
|
||||
|
||||
// 抖音
|
||||
douyinBinded: false,
|
||||
douyinPhone: ''
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadBindingStatus();
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// 每次显示时重新加载绑定状态
|
||||
this.loadBindingStatus();
|
||||
// 同时从后端加载
|
||||
this.loadUserProfile();
|
||||
},
|
||||
|
||||
// 从BACKEND加载用户信息(包含小红书绑定状态)
|
||||
async loadUserProfile() {
|
||||
try {
|
||||
const response = await EmployeeService.getProfile();
|
||||
|
||||
if (response.code === 200 && response.data) {
|
||||
const userInfo = response.data;
|
||||
const isBound = userInfo.is_bound_xhs === 1;
|
||||
// 使用has_xhs_cookie字段判断,而不是xhs_cookie
|
||||
const hasCookie = userInfo.has_xhs_cookie === true;
|
||||
|
||||
// 判断状态
|
||||
let statusText = '去绑定';
|
||||
let statusClass = '';
|
||||
let cookieExpired = false;
|
||||
|
||||
if (isBound) {
|
||||
if (hasCookie) {
|
||||
// 已绑定且Cookie有效
|
||||
statusText = '已绑定';
|
||||
statusClass = 'binded';
|
||||
} else {
|
||||
// 已绑定但Cookie失效
|
||||
statusText = '已失效';
|
||||
statusClass = 'expired';
|
||||
cookieExpired = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.setData({
|
||||
xiaohongshuBinded: isBound,
|
||||
xiaohongshuAccount: userInfo.xhs_account || '',
|
||||
xiaohongshuPhone: userInfo.xhs_phone || '',
|
||||
xiaohongshuCookieExpired: cookieExpired,
|
||||
xiaohongshuStatusText: statusText,
|
||||
xiaohongshuStatusClass: statusClass
|
||||
});
|
||||
|
||||
// 更新本地存储
|
||||
if (isBound) {
|
||||
const bindings = wx.getStorageSync('socialBindings') || {};
|
||||
bindings.xiaohongshu = {
|
||||
phone: userInfo.xhs_phone,
|
||||
xhs_account: userInfo.xhs_account,
|
||||
bindTime: userInfo.bound_at || new Date().getTime(),
|
||||
cookieExpired: cookieExpired
|
||||
};
|
||||
wx.setStorageSync('socialBindings', bindings);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载用户信息失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 加载绑定状态
|
||||
loadBindingStatus() {
|
||||
const bindings = wx.getStorageSync('socialBindings') || {};
|
||||
|
||||
this.setData({
|
||||
xiaohongshuBinded: !!bindings.xiaohongshu,
|
||||
xiaohongshuPhone: (bindings.xiaohongshu && bindings.xiaohongshu.phone) || '',
|
||||
|
||||
weiboBinded: !!bindings.weibo,
|
||||
weiboPhone: (bindings.weibo && bindings.weibo.phone) || '',
|
||||
|
||||
douyinBinded: !!bindings.douyin,
|
||||
douyinPhone: (bindings.douyin && bindings.douyin.phone) || ''
|
||||
});
|
||||
},
|
||||
|
||||
// 跳转到平台绑定页面
|
||||
goToPlatformBind(e: any) {
|
||||
const platform = e.currentTarget.dataset.platform;
|
||||
|
||||
// 如果是小红书
|
||||
if (platform === 'xiaohongshu') {
|
||||
// Cookie失效,直接跳转重新绑定
|
||||
if (this.data.xiaohongshuCookieExpired) {
|
||||
wx.navigateTo({
|
||||
url: '/pages/profile/platform-bind/platform-bind'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 已绑定且Cookie有效,显示解绑确认
|
||||
if (this.data.xiaohongshuBinded && !this.data.xiaohongshuCookieExpired) {
|
||||
this.handleUnbindXHS();
|
||||
return;
|
||||
}
|
||||
|
||||
// 未绑定,跳转到绑定页
|
||||
wx.navigateTo({
|
||||
url: '/pages/profile/platform-bind/platform-bind'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
wx.navigateTo({
|
||||
url: `/pages/profile/platform-bind/platform-bind?platform=${platform}`
|
||||
});
|
||||
},
|
||||
|
||||
// 解绑小红书
|
||||
handleUnbindXHS() {
|
||||
wx.showModal({
|
||||
title: '确认解绑',
|
||||
content: '确定要解绑小红书账号吗?',
|
||||
confirmText: '解绑',
|
||||
confirmColor: '#FF6B6B',
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
console.log('开始解绑小红书...');
|
||||
const response = await EmployeeService.unbindXHS();
|
||||
console.log('解绑响应:', response);
|
||||
|
||||
if (response.code === 200) {
|
||||
wx.showToast({
|
||||
title: '解绑成功',
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
// 清除本地存储
|
||||
const bindings = wx.getStorageSync('socialBindings') || {};
|
||||
delete bindings.xiaohongshu;
|
||||
wx.setStorageSync('socialBindings', bindings);
|
||||
|
||||
// 刷新页面
|
||||
this.setData({
|
||||
xiaohongshuBinded: false,
|
||||
xiaohongshuPhone: '',
|
||||
xiaohongshuAccount: ''
|
||||
});
|
||||
|
||||
// 重新加载用户信息
|
||||
this.loadUserProfile();
|
||||
} else {
|
||||
console.error('解绑失败:', response.message);
|
||||
wx.showToast({
|
||||
title: response.message || '解绑失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('解绑失败:', error);
|
||||
wx.showToast({
|
||||
title: '解绑失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,51 +0,0 @@
|
||||
<!--pages/profile/social-binding/social-binding.wxml-->
|
||||
<view class="page-container">
|
||||
<scroll-view class="content-scroll" scroll-y>
|
||||
|
||||
<!-- 小红书 -->
|
||||
<view class="platform-item" bindtap="goToPlatformBind" data-platform="xiaohongshu">
|
||||
<view class="platform-left">
|
||||
<view class="platform-icon xiaohongshu"></view>
|
||||
<view class="platform-info">
|
||||
<text class="platform-name">小红书</text>
|
||||
<text class="platform-desc">{{xiaohongshuBinded ? xiaohongshuPhone : '未绑定'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="platform-right">
|
||||
<view class="bind-status {{xiaohongshuStatusClass}}">{{xiaohongshuStatusText}}</view>
|
||||
<text class="item-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 微博 -->
|
||||
<view class="platform-item" bindtap="goToPlatformBind" data-platform="weibo">
|
||||
<view class="platform-left">
|
||||
<view class="platform-icon weibo"></view>
|
||||
<view class="platform-info">
|
||||
<text class="platform-name">微博</text>
|
||||
<text class="platform-desc">{{weiboBinded ? weiboPhone : '未绑定'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="platform-right">
|
||||
<view class="bind-status {{weiboBinded ? 'binded' : ''}}">{{weiboBinded ? '已绑定' : '去绑定'}}</view>
|
||||
<text class="item-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 抖音 -->
|
||||
<view class="platform-item" bindtap="goToPlatformBind" data-platform="douyin">
|
||||
<view class="platform-left">
|
||||
<view class="platform-icon douyin"></view>
|
||||
<view class="platform-info">
|
||||
<text class="platform-name">抖音</text>
|
||||
<text class="platform-desc">{{douyinBinded ? douyinPhone : '未绑定'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="platform-right">
|
||||
<view class="bind-status {{douyinBinded ? 'binded' : ''}}">{{douyinBinded ? '已绑定' : '去绑定'}}</view>
|
||||
<text class="item-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</scroll-view>
|
||||
</view>
|
||||
@@ -1,112 +0,0 @@
|
||||
/* pages/profile/social-binding/social-binding.wxss */
|
||||
page {
|
||||
background: #f8f8f8;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.content-scroll {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
padding: 20rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 平台列表项 */
|
||||
.platform-item {
|
||||
background: white;
|
||||
border-radius: 16rpx;
|
||||
padding: 32rpx;
|
||||
margin-bottom: 20rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.platform-item:active {
|
||||
transform: scale(0.98);
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.platform-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.platform-icon {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
border-radius: 16rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.platform-icon.xiaohongshu {
|
||||
background: #07c160;
|
||||
}
|
||||
|
||||
.platform-icon.weibo {
|
||||
background: linear-gradient(135deg, #ff8200 0%, #ffb84d 100%);
|
||||
}
|
||||
|
||||
.platform-icon.douyin {
|
||||
background: linear-gradient(135deg, #000000 0%, #333333 100%);
|
||||
}
|
||||
|
||||
.platform-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.platform-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.platform-desc {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.platform-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.bind-status {
|
||||
padding: 8rpx 20rpx;
|
||||
border-radius: 20rpx;
|
||||
font-size: 24rpx;
|
||||
background: #f5f5f5;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.bind-status.binded {
|
||||
background: #e8f5e9;
|
||||
color: #4caf50;
|
||||
}
|
||||
|
||||
.bind-status.expired {
|
||||
background: #fff3e0;
|
||||
color: #ff9800;
|
||||
}
|
||||
|
||||
.item-arrow {
|
||||
font-size: 40rpx;
|
||||
color: #d0d0d0;
|
||||
font-weight: 300;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"navigationBarTitleText": "个人资料",
|
||||
"navigationBarBackgroundColor": "#07c160",
|
||||
"navigationBarTextStyle": "white"
|
||||
}
|
||||
@@ -1,171 +0,0 @@
|
||||
// pages/profile/user-info/user-info.ts
|
||||
import { EmployeeService } from '../../../services/employee';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
username: '',
|
||||
nickname: '',
|
||||
enterpriseName: '',
|
||||
avatar: '',
|
||||
phone: '',
|
||||
email: '',
|
||||
role: '',
|
||||
roleText: '',
|
||||
saving: false
|
||||
},
|
||||
|
||||
async onLoad() {
|
||||
await this.loadUserInfo();
|
||||
},
|
||||
|
||||
async loadUserInfo() {
|
||||
try {
|
||||
const response = await EmployeeService.getProfile();
|
||||
if (response.code === 200 && response.data) {
|
||||
const userInfo: any = response.data;
|
||||
const role = userInfo.role || '';
|
||||
const nickname = userInfo.nickname || userInfo.name || userInfo.username || '';
|
||||
|
||||
this.setData({
|
||||
username: userInfo.name || '',
|
||||
nickname,
|
||||
enterpriseName: userInfo.enterprise_name || '',
|
||||
avatar: userInfo.avatar || '',
|
||||
phone: userInfo.phone || '',
|
||||
email: userInfo.email || '',
|
||||
role,
|
||||
roleText: this.translateRole(role)
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载个人信息失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
translateRole(role: string): string {
|
||||
switch (role) {
|
||||
case 'admin':
|
||||
return '管理员';
|
||||
case 'reviewer':
|
||||
return '审核员';
|
||||
case 'publisher':
|
||||
return '发布员';
|
||||
default:
|
||||
return '内容管理员';
|
||||
}
|
||||
},
|
||||
|
||||
onNicknameInput(e: any) {
|
||||
this.setData({ nickname: e.detail.value });
|
||||
},
|
||||
|
||||
onEmailInput(e: any) {
|
||||
this.setData({ email: e.detail.value });
|
||||
},
|
||||
|
||||
async onChooseWechatAvatar(e: any) {
|
||||
if (this.data.saving) return;
|
||||
|
||||
const avatarUrl = e.detail.avatarUrl;
|
||||
if (!avatarUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
wx.showLoading({ title: '上传中...', mask: true });
|
||||
const uploadRes = await EmployeeService.uploadImage(avatarUrl);
|
||||
wx.hideLoading();
|
||||
|
||||
if (uploadRes.code === 200 && uploadRes.data) {
|
||||
this.setData({ avatar: uploadRes.data.image_url });
|
||||
} else {
|
||||
wx.showToast({ title: uploadRes.message || '上传失败', icon: 'none' });
|
||||
}
|
||||
} catch (error: any) {
|
||||
wx.hideLoading();
|
||||
if (error && error.errMsg && error.errMsg.indexOf('cancel') !== -1) {
|
||||
return;
|
||||
}
|
||||
console.error('选择头像失败:', error);
|
||||
wx.showToast({ title: '选择头像失败', icon: 'none' });
|
||||
}
|
||||
},
|
||||
|
||||
onUseWechatNickname() {
|
||||
if (this.data.saving) return;
|
||||
|
||||
wx.getUserProfile({
|
||||
desc: '用于完善个人资料',
|
||||
success: (res) => {
|
||||
const nickname = (res.userInfo && res.userInfo.nickName) || '';
|
||||
|
||||
if (!nickname) {
|
||||
wx.showToast({ title: '未获取到微信昵称', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
this.setData({
|
||||
nickname
|
||||
});
|
||||
},
|
||||
fail: (error) => {
|
||||
if (error && error.errMsg && error.errMsg.indexOf('auth deny') !== -1) {
|
||||
wx.showToast({ title: '未授权微信昵称', icon: 'none' });
|
||||
} else {
|
||||
wx.showToast({ title: '获取微信昵称失败', icon: 'none' });
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
onFormSubmit(e: any) {
|
||||
const { nickname, email } = e.detail.value || {};
|
||||
|
||||
this.setData({
|
||||
nickname,
|
||||
email
|
||||
}, () => {
|
||||
this.handleSave();
|
||||
});
|
||||
},
|
||||
|
||||
async handleSave() {
|
||||
if (this.data.saving) return;
|
||||
|
||||
const { nickname, email, avatar } = this.data;
|
||||
|
||||
if (!nickname || nickname.trim().length === 0) {
|
||||
wx.showToast({ title: '昵称不能为空', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (email && email.indexOf('@') === -1) {
|
||||
wx.showToast({ title: '邮箱格式不正确', icon: 'none' });
|
||||
return;
|
||||
}
|
||||
|
||||
this.setData({ saving: true });
|
||||
wx.showLoading({ title: '保存中...', mask: true });
|
||||
|
||||
try {
|
||||
const res = await EmployeeService.updateProfile({
|
||||
nickname: nickname.trim(),
|
||||
email: email ? email.trim() : undefined,
|
||||
avatar
|
||||
});
|
||||
|
||||
wx.hideLoading();
|
||||
if (res.code === 200) {
|
||||
wx.showToast({ title: '保存成功', icon: 'success' });
|
||||
} else {
|
||||
wx.showToast({ title: res.message || '保存失败', icon: 'none' });
|
||||
}
|
||||
} catch (error) {
|
||||
wx.hideLoading();
|
||||
console.error('保存个人资料失败:', error);
|
||||
wx.showToast({ title: '保存失败', icon: 'none' });
|
||||
} finally {
|
||||
this.setData({ saving: false });
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,57 +0,0 @@
|
||||
<!--pages/profile/user-info/user-info.wxml-->
|
||||
<view class="page-container">
|
||||
<form bindsubmit="onFormSubmit">
|
||||
<!-- 资料编辑区域 -->
|
||||
<view class="info-section">
|
||||
<!-- 头像,使用微信官方选择头像能力 -->
|
||||
<view class="info-item">
|
||||
<view class="item-label">头像</view>
|
||||
<view class="item-value">
|
||||
<button class="avatar-btn" open-type="chooseAvatar" bindchooseavatar="onChooseWechatAvatar">
|
||||
<view class="avatar-preview">
|
||||
<image wx:if="{{avatar}}" class="avatar-img-small" src="{{avatar}}" mode="aspectFill" />
|
||||
<text wx:else class="avatar-icon"></text>
|
||||
</view>
|
||||
</button>
|
||||
<text class="item-arrow">›</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 昵称,可编辑 -->
|
||||
<view class="info-item">
|
||||
<view class="item-label">昵称</view>
|
||||
<view class="item-value">
|
||||
<input class="value-input" name="nickname" type="nickname" value="{{nickname}}" placeholder="请输入昵称" maxlength="20" bindinput="onNicknameInput" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 邮箱,可编辑 -->
|
||||
<view class="info-item">
|
||||
<view class="item-label">邮箱</view>
|
||||
<view class="item-value">
|
||||
<input class="value-input" name="email" value="{{email}}" placeholder="请输入邮箱" bindinput="onEmailInput" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 手机号,只读 -->
|
||||
<view class="info-item">
|
||||
<view class="item-label">手机号</view>
|
||||
<view class="item-value">
|
||||
<text class="value-text">{{phone || '未绑定'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 角色,只读 -->
|
||||
<view class="info-item">
|
||||
<view class="item-label">角色</view>
|
||||
<view class="item-value">
|
||||
<text class="value-text role">{{roleText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="save-section">
|
||||
<button class="save-btn" loading="{{saving}}" disabled="{{saving}}" form-type="submit">保存修改</button>
|
||||
</view>
|
||||
</form>
|
||||
</view>
|
||||
@@ -1,190 +0,0 @@
|
||||
/* pages/profile/user-info/user-info.wxss */
|
||||
page {
|
||||
background: #f8f8f8;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
min-height: 100vh;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
|
||||
/* 头部区域,统一为绿色背景,与个人中心一致 */
|
||||
.header-section {
|
||||
width: 100%;
|
||||
background: #07c160;
|
||||
padding: 50rpx 30rpx 70rpx;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.user-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 60rpx;
|
||||
background: #ffffff;
|
||||
border: 4rpx solid rgba(255, 255, 255, 0.3);
|
||||
margin-right: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.avatar-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 60rpx;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.username {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.enterprise-name {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.info-section {
|
||||
width: 100%;
|
||||
background: #ffffff;
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 32rpx 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.info-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-label {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.item-value {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
flex: 1;
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
.value-text {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.value-text.role {
|
||||
color: #07c160;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.value-input {
|
||||
min-width: 360rpx;
|
||||
text-align: right;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.item-arrow {
|
||||
font-size: 36rpx;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
.avatar-preview {
|
||||
width: 72rpx;
|
||||
height: 72rpx;
|
||||
border-radius: 50%;
|
||||
background: #f5f5f5;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.avatar-img-small {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.avatar-btn {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.avatar-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.avatar-icon {
|
||||
width: 50rpx;
|
||||
height: 50rpx;
|
||||
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23ffffff"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></svg>');
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.wechat-sync-btn {
|
||||
padding: 12rpx 24rpx;
|
||||
font-size: 24rpx;
|
||||
color: #07c160;
|
||||
border-radius: 999rpx;
|
||||
border: 1rpx solid #07c160;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
.wechat-sync-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.save-section {
|
||||
width: 100%;
|
||||
padding: 40rpx 30rpx;
|
||||
}
|
||||
|
||||
.save-btn {
|
||||
width: 80%;
|
||||
max-width: 600rpx;
|
||||
margin: 0 auto;
|
||||
background: #07c160;
|
||||
color: #ffffff;
|
||||
border: none;
|
||||
border-radius: 999rpx;
|
||||
padding: 24rpx 0;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
box-shadow: 0 8rpx 24rpx rgba(7, 193, 96, 0.3);
|
||||
}
|
||||
|
||||
.save-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.save-btn:active {
|
||||
opacity: 0.9;
|
||||
transform: translateY(2rpx);
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"navigationBarTitleText": "小红书登录",
|
||||
"navigationBarBackgroundColor": "#ffffff",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
@@ -1,291 +0,0 @@
|
||||
// pages/profile/xhs-login/xhs-login.ts
|
||||
import { EmployeeService } from '../../../services/employee';
|
||||
|
||||
Page({
|
||||
data: {
|
||||
countryCode: '+86',
|
||||
phone: '',
|
||||
code: '',
|
||||
codeSending: false,
|
||||
countdown: 0,
|
||||
agreedToTerms: false,
|
||||
showAgreementModal: false,
|
||||
loginLoading: false // 绑定加载状态,防止重复提交
|
||||
},
|
||||
|
||||
// 选择国家区号
|
||||
selectCountryCode() {
|
||||
const codes = ['+86', '+852', '+853', '+886'];
|
||||
const names = ['中国大陆', '中国香港', '中国澳门', '中国台湾'];
|
||||
|
||||
wx.showActionSheet({
|
||||
itemList: names.map((name, index) => `${name} ${codes[index]}`),
|
||||
success: (res) => {
|
||||
this.setData({
|
||||
countryCode: codes[res.tapIndex]
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 手机号输入
|
||||
onPhoneInput(e: any) {
|
||||
this.setData({
|
||||
phone: e.detail.value
|
||||
});
|
||||
},
|
||||
|
||||
// 验证码输入
|
||||
onCodeInput(e: any) {
|
||||
this.setData({
|
||||
code: e.detail.value
|
||||
});
|
||||
},
|
||||
|
||||
// 协议勾选变化
|
||||
onAgreementChange(e: any) {
|
||||
this.setData({
|
||||
agreedToTerms: e.detail.value.length > 0
|
||||
});
|
||||
},
|
||||
|
||||
// 发送验证码
|
||||
async sendCode() {
|
||||
const phone = this.data.phone;
|
||||
|
||||
// 验证手机号
|
||||
if (!phone || phone.length !== 11) {
|
||||
wx.showToast({
|
||||
title: '请输入正确的手机号',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 手机号格式验证
|
||||
const phoneReg = /^1[3-9]\d{9}$/;
|
||||
if (!phoneReg.test(phone)) {
|
||||
wx.showToast({
|
||||
title: '手机号格式不正确',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 防止重复发送
|
||||
if (this.data.codeSending || this.data.countdown > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置发送状态
|
||||
this.setData({
|
||||
codeSending: true
|
||||
});
|
||||
|
||||
try {
|
||||
console.log('开始发送验证码,手机号:', phone);
|
||||
|
||||
// 调用后端API发送验证码(showLoading=true,显示加载提示)
|
||||
const response = await EmployeeService.sendXHSCode(phone, true);
|
||||
|
||||
console.log('发送验证码响应:', response);
|
||||
|
||||
if (response.code === 200) {
|
||||
wx.showToast({
|
||||
title: '验证码已发送',
|
||||
icon: 'success'
|
||||
});
|
||||
this.startCountdown();
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: response.message || '发送失败',
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
this.setData({
|
||||
codeSending: false
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('发送验证码失败:', error);
|
||||
|
||||
// 检查是否是超时错误
|
||||
const errorMsg = error && typeof error === 'object' && 'message' in error
|
||||
? (error as any).message
|
||||
: '发送失败,请重试';
|
||||
|
||||
wx.showToast({
|
||||
title: errorMsg,
|
||||
icon: 'none',
|
||||
duration: 3000
|
||||
});
|
||||
|
||||
this.setData({
|
||||
codeSending: false
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 倒计时
|
||||
startCountdown() {
|
||||
let countdown = 180;
|
||||
|
||||
this.setData({
|
||||
countdown: countdown,
|
||||
codeSending: true
|
||||
});
|
||||
|
||||
const timer = setInterval(() => {
|
||||
countdown--;
|
||||
|
||||
if (countdown <= 0) {
|
||||
clearInterval(timer);
|
||||
this.setData({
|
||||
countdown: 0,
|
||||
codeSending: false
|
||||
});
|
||||
} else {
|
||||
this.setData({
|
||||
countdown: countdown
|
||||
});
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
// 登录
|
||||
async login() {
|
||||
const phone = this.data.phone;
|
||||
const code = this.data.code;
|
||||
|
||||
// 检查是否同意协议
|
||||
if (!this.data.agreedToTerms) {
|
||||
this.setData({
|
||||
showAgreementModal: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证手机号
|
||||
if (!phone || phone.length !== 11) {
|
||||
wx.showToast({
|
||||
title: '请输入正确的手机号',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证验证码
|
||||
if (!code || code.length !== 6) {
|
||||
wx.showToast({
|
||||
title: '请输入6位验证码',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 防止重复提交(关键优化)
|
||||
if (this.data.loginLoading) {
|
||||
console.log('绑定请求进行中,忽略重复点击');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 设置 loading 状态
|
||||
this.setData({
|
||||
loginLoading: true
|
||||
});
|
||||
|
||||
// 调用后端API绑定小红书
|
||||
const response = await EmployeeService.bindXHS(phone, code);
|
||||
|
||||
if (response.code === 200) {
|
||||
// 绑定成功,保存绑定信息
|
||||
const bindings = wx.getStorageSync('socialBindings') || {};
|
||||
bindings.xiaohongshu = {
|
||||
phone: phone,
|
||||
bindTime: new Date().getTime(),
|
||||
xhs_account: (response.data && response.data.xhs_account) || ''
|
||||
};
|
||||
wx.setStorageSync('socialBindings', bindings);
|
||||
|
||||
wx.showToast({
|
||||
title: '绑定成功',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
});
|
||||
|
||||
// 延迟500毫秒后返回,让用户看到成功提示
|
||||
setTimeout(() => {
|
||||
// 重置 loading 状态
|
||||
this.setData({
|
||||
loginLoading: false
|
||||
});
|
||||
// 返回上一页(社交账号绑定页)
|
||||
wx.navigateBack({
|
||||
delta: 1
|
||||
});
|
||||
}, 1500);
|
||||
} else {
|
||||
// 绑定失败,重置 loading
|
||||
this.setData({
|
||||
loginLoading: false
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('绑定小红书失败:', error);
|
||||
// 重置 loading 状态
|
||||
this.setData({
|
||||
loginLoading: false
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 关闭协议弹窗
|
||||
closeAgreementModal() {
|
||||
this.setData({
|
||||
showAgreementModal: false
|
||||
});
|
||||
},
|
||||
|
||||
// 同意并登录
|
||||
agreeAndLogin() {
|
||||
this.setData({
|
||||
agreedToTerms: true,
|
||||
showAgreementModal: false
|
||||
});
|
||||
|
||||
// 延迟执行登录,让用户看到勾选效果
|
||||
setTimeout(() => {
|
||||
this.login();
|
||||
}, 300);
|
||||
},
|
||||
|
||||
// 阻止事件冒泡
|
||||
stopPropagation() {},
|
||||
|
||||
// 跳转到用户协议
|
||||
goToUserAgreement(e: any) {
|
||||
e.stopPropagation();
|
||||
wx.navigateTo({
|
||||
url: '/pages/agreement/user-agreement/user-agreement'
|
||||
});
|
||||
},
|
||||
|
||||
// 跳转到隐私政策
|
||||
goToPrivacy(e: any) {
|
||||
e.stopPropagation();
|
||||
wx.navigateTo({
|
||||
url: '/pages/agreement/privacy-policy/privacy-policy'
|
||||
});
|
||||
},
|
||||
|
||||
// 跳转到个人信息保护政策
|
||||
goToPersonalInfo(e: any) {
|
||||
e.stopPropagation();
|
||||
// TODO: 创建个人信息保护政策页面
|
||||
wx.showToast({
|
||||
title: '功能开发中',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -1,80 +0,0 @@
|
||||
<!--pages/profile/xhs-login/xhs-login.wxml-->
|
||||
<view class="page-container">
|
||||
<view class="platform-header">
|
||||
<view class="platform-icon xiaohongshu"></view>
|
||||
<view class="platform-text">
|
||||
<text class="platform-name">小红书</text>
|
||||
<text class="platform-tip">绑定后可同步发布内容</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 未绑定状态 -->
|
||||
<view class="bind-form">
|
||||
<!-- 手机号 -->
|
||||
<view class="form-item">
|
||||
<view class="phone-input-wrapper">
|
||||
<view class="country-code" bindtap="selectCountryCode">
|
||||
<text class="code-text">{{countryCode}}</text>
|
||||
<text class="arrow-down">▼</text>
|
||||
</view>
|
||||
<input
|
||||
class="phone-input"
|
||||
type="number"
|
||||
maxlength="11"
|
||||
placeholder="请输入手机号"
|
||||
value="{{phone}}"
|
||||
bindinput="onPhoneInput"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 验证码 -->
|
||||
<view class="form-item">
|
||||
<view class="code-input-wrapper">
|
||||
<input
|
||||
class="code-input"
|
||||
type="number"
|
||||
maxlength="6"
|
||||
placeholder="请输入验证码"
|
||||
value="{{code}}"
|
||||
bindinput="onCodeInput"
|
||||
/>
|
||||
<view
|
||||
class="send-code-text {{codeSending ? 'disabled' : ''}}"
|
||||
bindtap="sendCode"
|
||||
>
|
||||
{{countdown > 0 ? '重新发送(' + countdown + 's)' : '获取验证码'}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<button class="bind-btn" bindtap="login">
|
||||
确认
|
||||
</button>
|
||||
|
||||
<!-- 协议提示 -->
|
||||
<view class="agreement-tip">
|
||||
<text class="tip-icon">⚠️</text>
|
||||
<text class="tip-text">我已阅读并同意</text>
|
||||
<text class="tip-link" bindtap="goToUserAgreement">《用户协议》</text>
|
||||
<text class="tip-text">、</text>
|
||||
<text class="tip-link" bindtap="goToPrivacy">《隐私政策》</text>
|
||||
<text class="tip-text">、</text>
|
||||
<text class="tip-link" bindtap="goToPersonalInfo">《个人信息保护政策》</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 提示弹窗 -->
|
||||
<view class="modal-mask" wx:if="{{showAgreementModal}}" bindtap="closeAgreementModal">
|
||||
<view class="modal-dialog" catchtap="stopPropagation">
|
||||
<view class="modal-title">温馨提示</view>
|
||||
<view class="modal-content">
|
||||
请先同意《用户协议》和《隐私政策》后再登录
|
||||
</view>
|
||||
<view class="modal-footer">
|
||||
<button class="modal-btn cancel" bindtap="closeAgreementModal">不同意</button>
|
||||
<button class="modal-btn confirm" bindtap="agreeAndLogin">同意</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -1,256 +0,0 @@
|
||||
/* pages/profile/xhs-login/xhs-login.wxss */
|
||||
page {
|
||||
background: #f8f8f8;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
padding: 30rpx;
|
||||
min-height: 100vh;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 平台头部 */
|
||||
.platform-header {
|
||||
background: white;
|
||||
border-radius: 16rpx;
|
||||
padding: 40rpx;
|
||||
margin-bottom: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.platform-icon {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 20rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.platform-icon.xiaohongshu {
|
||||
background: #07c160;
|
||||
}
|
||||
|
||||
.platform-text {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.platform-name {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.platform-tip {
|
||||
font-size: 26rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 表单 */
|
||||
.bind-form {
|
||||
background: white;
|
||||
border-radius: 16rpx;
|
||||
padding: 40rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.form-item {
|
||||
margin-bottom: 32rpx;
|
||||
}
|
||||
|
||||
.form-item:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* 手机号输入 */
|
||||
.phone-input-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 88rpx;
|
||||
background: #f8f8f8;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.country-code {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
padding: 0 20rpx;
|
||||
height: 100%;
|
||||
border-right: 1rpx solid #e0e0e0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.code-text {
|
||||
font-size: 28rpx;
|
||||
color: #1a1a1a;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.arrow-down {
|
||||
font-size: 20rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.phone-input {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
padding: 0 24rpx;
|
||||
font-size: 28rpx;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
/* 验证码输入 */
|
||||
.code-input-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 88rpx;
|
||||
background: #f8f8f8;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.code-input {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
padding: 0 24rpx;
|
||||
font-size: 28rpx;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
.send-code-text {
|
||||
padding: 0 24rpx;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 26rpx;
|
||||
color: #07c160;
|
||||
white-space: nowrap;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.send-code-text.disabled {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.bind-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: #07c160;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 44rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
margin-top: 40rpx;
|
||||
margin-bottom: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.bind-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* 协议提示 */
|
||||
.agreement-tip {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
gap: 4rpx;
|
||||
padding: 0 8rpx;
|
||||
}
|
||||
|
||||
.tip-icon {
|
||||
font-size: 24rpx;
|
||||
margin-right: 4rpx;
|
||||
}
|
||||
|
||||
.tip-text {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.tip-link {
|
||||
font-size: 22rpx;
|
||||
color: #07c160;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* 提示弹窗 */
|
||||
.modal-mask {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.modal-dialog {
|
||||
width: 560rpx;
|
||||
background: white;
|
||||
border-radius: 24rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.modal-title {
|
||||
padding: 40rpx 32rpx 24rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #1a1a1a;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
padding: 0 32rpx 40rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
display: flex;
|
||||
border-top: 1rpx solid #e0e0e0;
|
||||
}
|
||||
|
||||
.modal-btn {
|
||||
flex: 1;
|
||||
height: 96rpx;
|
||||
background: white;
|
||||
border: none;
|
||||
font-size: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.modal-btn::after {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.modal-btn.cancel {
|
||||
color: #666;
|
||||
border-right: 1rpx solid #e0e0e0;
|
||||
}
|
||||
|
||||
.modal-btn.confirm {
|
||||
color: #07c160;
|
||||
font-weight: 600;
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
<!--pages/profile/xhs-publish/xhs-publish.wxml-->
|
||||
<view class="page-container">
|
||||
<!-- 渐变红背景 + 动画效果 -->
|
||||
<view class="background">
|
||||
<view class="gradient-bg"></view>
|
||||
<view class="circle circle1"></view>
|
||||
<view class="circle circle2"></view>
|
||||
<view class="circle circle3"></view>
|
||||
</view>
|
||||
|
||||
<!-- 发布卡片 - 毛玻璃效果 -->
|
||||
<view class="publish-card">
|
||||
<view class="card-header">
|
||||
<text class="header-title">✨ 发布小红书笔记</text>
|
||||
<text class="header-subtitle">分享你的精彩时刻</text>
|
||||
</view>
|
||||
|
||||
<!-- 标题输入 -->
|
||||
<view class="input-group">
|
||||
<view class="input-label">
|
||||
<text class="label-icon">📝</text>
|
||||
<text class="label-text">标题</text>
|
||||
</view>
|
||||
<input
|
||||
class="input-field"
|
||||
type="text"
|
||||
placeholder="给你的笔记起个吸引人的标题"
|
||||
value="{{title}}"
|
||||
bindinput="onTitleInput"
|
||||
maxlength="30"
|
||||
/>
|
||||
<view class="char-count">{{title.length}}/30</view>
|
||||
</view>
|
||||
|
||||
<!-- 内容输入 -->
|
||||
<view class="input-group">
|
||||
<view class="input-label">
|
||||
<text class="label-icon">✍️</text>
|
||||
<text class="label-text">正文内容</text>
|
||||
</view>
|
||||
<textarea
|
||||
class="textarea-field"
|
||||
placeholder="分享你的故事、经验或想法..."
|
||||
value="{{content}}"
|
||||
bindinput="onContentInput"
|
||||
maxlength="1000"
|
||||
auto-height
|
||||
></textarea>
|
||||
<view class="char-count">{{content.length}}/1000</view>
|
||||
</view>
|
||||
|
||||
<!-- 话题标签 -->
|
||||
<view class="input-group">
|
||||
<view class="input-label">
|
||||
<text class="label-icon">🏷️</text>
|
||||
<text class="label-text">话题标签</text>
|
||||
<text class="label-tip">(可选)</text>
|
||||
</view>
|
||||
<input
|
||||
class="input-field"
|
||||
type="text"
|
||||
placeholder="输入话题后按空格分隔,如:旅行 美食 生活"
|
||||
value="{{topicsText}}"
|
||||
bindinput="onTopicsInput"
|
||||
/>
|
||||
<view class="topics-preview" wx:if="{{topics.length > 0}}">
|
||||
<block wx:for="{{topics}}" wx:key="index">
|
||||
<view class="topic-tag">#{{item}}#</view>
|
||||
</block>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 提示信息 -->
|
||||
<view class="tips-box">
|
||||
<text class="tips-icon">💡</text>
|
||||
<text class="tips-text">发布前请确保已登录小红书账号</text>
|
||||
</view>
|
||||
|
||||
<!-- 发布按钮 -->
|
||||
<button
|
||||
class="publish-btn {{publishing ? 'disabled' : ''}}"
|
||||
bindtap="handlePublish"
|
||||
disabled="{{publishing}}"
|
||||
>
|
||||
<text wx:if="{{!publishing}}">🚀 立即发布</text>
|
||||
<text wx:else>发布中...</text>
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- Toast提示 -->
|
||||
<view class="toast {{showToast ? 'show' : ''}}" wx:if="{{toastMessage}}">
|
||||
<text>{{toastMessage}}</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -72,9 +72,10 @@ export interface PublishRecord {
|
||||
export class EmployeeService {
|
||||
/**
|
||||
* 发送小红书验证码
|
||||
* 返回 session_id 用于后续复用浏览器
|
||||
*/
|
||||
static async sendXHSCode(xhsPhone: string, showLoading = true) {
|
||||
return post(API.xhs.sendCode, {
|
||||
return post<{ sent_at: string; session_id: string }>(API.xhs.sendCode, {
|
||||
xhs_phone: xhsPhone
|
||||
}, showLoading);
|
||||
}
|
||||
@@ -88,11 +89,16 @@ export class EmployeeService {
|
||||
|
||||
/**
|
||||
* 绑定小红书账号
|
||||
* @param xhsPhone 小红书手机号
|
||||
* @param code 验证码
|
||||
* @param sessionId 发送验证码时返回的session_id,用于复用浏览器
|
||||
* @param showLoading 是否显示加载动画
|
||||
*/
|
||||
static async bindXHS(xhsPhone: string, code: string, showLoading = false) {
|
||||
static async bindXHS(xhsPhone: string, code: string, sessionId?: string, showLoading = false) {
|
||||
return post<{ xhs_account: string }>(API.employee.bindXHS, {
|
||||
xhs_phone: xhsPhone,
|
||||
code
|
||||
code,
|
||||
session_id: sessionId // 传递session_id
|
||||
}, showLoading);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,8 +51,8 @@ export function request<T = any>(options: RequestOptions): Promise<ApiResponse<T
|
||||
|
||||
const response = res.data as ApiResponse<T>;
|
||||
|
||||
// 处理业务状态码
|
||||
if (response.code === 200) {
|
||||
// 处理业务状态码(兼容 code=0 和 code=200)
|
||||
if (response.code === 200 || response.code === 0) {
|
||||
resolve(response);
|
||||
} else if (response.code === 401) {
|
||||
// Token过期或未登录
|
||||
|
||||
Reference in New Issue
Block a user