daShangDao_miniProgram/pages/scan/history.vue
2026-06-15 16:37:57 +08:00

2100 lines
63 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="u-page">
<!-- 账号密码模块 -->
<view class="u-demo-block">
<view v-if="!isLoggedIn">
<view class="section-header custom-layout">
<text class="section-title" style="flex: 1; min-width: 200rpx; white-space: nowrap;">账号密码</text>
<text class="section-subtitle"
style="flex: 1; text-align: right; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">输入孔网账号密码</text>
</view>
<view class="login-form-row">
<!-- 用户名输入框 -->
<u--input placeholder="请输入账号" v-model="username" class="login-input"></u--input>
<!-- 密码输入框 -->
<u--input placeholder="请输入密码" type="password" v-model="password" class="login-input"></u--input>
<!-- 登录按钮 -->
<button text="登录" size="mini" @click="login" :loading="isLoading" :disabled="isLoading"
:customStyle="{
flex: '1',
minWidth: '80rpx',
maxWidth: '80rpx',
whiteSpace: 'nowrap',
height: '70rpx',
backgroundColor: isLoading ? '#e0e0e0' : '#ffffff'
}">{{ isLoading ? '正在登录...' : '登录' }}</button>
</view>
<!-- 记住密码选项 -->
<view class="remember-password">
<checkbox-group @change="handleRememberPasswordChange">
<label class="checkbox-label">
<checkbox :checked="rememberPassword" value="1" style="transform:scale(0.7)" color="#007AFF" />
<text>记住密码</text>
</label>
</checkbox-group>
</view>
</view>
<!-- 用户信息展示 -->
<view v-else class="user-info">
<view class="user-avatar">
<image :src="userInfo && userInfo.photo ? userInfo.photo : '/static/admin-avatar.png'"
mode="aspectFill"></image>
</view>
<view class="user-details">
<text class="username">{{userInfo && userInfo.nickname ? userInfo.nickname : username}}</text>
<text class="user-area">{{userInfo && userInfo.areaName ? userInfo.areaName : ''}}</text>
</view>
<text class="logout" @click="handleLogout">退出登录</text>
</view>
<!-- 账号管理(登录前后都显示) -->
<view class="accounts-manager">
<view class="section-header" style="padding-top: 10rpx;">
<text class="section-title" style="font-size: 26rpx;">账号管理</text>
<view class="add-account" @click="showAddAccount">+ 添加账号</view>
</view>
<!-- 账号列表 -->
<view class="account-list">
<view class="account-item" v-for="(account, index) in accounts" :key="index">
<view class="account-info">
<text class="account-username">{{account.username}}</text>
<text class="account-status" :class="{'active': account.isActive}">{{account.isActive ? '当前使用' : '备用'}}</text>
</view>
<view class="account-actions">
<text class="action-btn" @click="setAsActive(index)" v-if="!account.isActive">使用</text>
<text class="action-btn delete" @click="removeAccount(index)" v-if="!account.isActive">删除</text>
</view>
</view>
</view>
</view>
<!-- 添加账号弹窗 -->
<uni-popup ref="accountPopup" type="center">
<view class="add-account-popup">
<view class="popup-title">添加备用账号</view>
<view class="popup-form">
<u--input placeholder="请输入账号" v-model="newAccount.username" class="popup-input" border="surround"></u--input>
<u--input placeholder="请输入密码" type="password" v-model="newAccount.password" class="popup-input" border="surround"></u--input>
</view>
<view class="popup-actions">
<button class="popup-btn cancel" @click="closePopup">取消</button>
<button class="popup-btn confirm" @click="addAccount">确认</button>
</view>
</view>
</uni-popup>
</view>
<!-- 屏蔽店铺模块 -->
<view class="u-demo-block">
<text class="section-title">屏蔽店铺</text>
<u--textarea v-model="value1" placeholder="在售商品列中不显示的店铺(屏蔽店铺之间使用;分割)"
:inputStyle="{ fontSize: '32rpx !important' }"
placeholder-style="font-size: 32rpx !important"></u--textarea>
</view>
<!-- 价格模式模块 -->
<view class="u-demo-block">
<view class="section-header">
<text class="section-title">价格模式(总价=书价+运费)</text>
<text class="section-subtitle">自动生成改价</text>
</view>
<view class="u-demo-block__content">
<!-- 选项卡组件展示价格模式选项current1控制当前选中项选项变化时触发change1方法 -->
<u-subsection :list="list" mode="button" :current="current1" @change="change1"
activeColor="#000000"></u-subsection>
<view class="price-reference" style="color:#888;font-size:28rpx; margin:20rpx 0;">
<!-- 根据current1的值显示不同的提示文本 -->
<text v-if="current1 === 0">以最低价的<text class="highlight-text">总价</text>为参照物</text>
<text v-if="current1 === 1">以<text class="highlight-text">总价</text>最低的<text
class="highlight-text">{{averageRange}}</text>个价格平均值为参照物</text>
<!-- 数字输入框当current1为1时显示双向绑定averageRange设置取值范围和步长 -->
<view v-if="current1 === 1" class="average-range-control">
<text class="range-label">参考值个数(2-12之间)</text>
<view class="range-control">
<text class="range-btn" @click="decreaseRange"></text>
<text class="range-value">{{averageRange}}</text>
<text class="range-btn" @click="increaseRange"></text>
</view>
</view>
<!-- 当选择最低价时,显示排序位置选择器 -->
<view v-if="current1 === 0" class="position-selector">
<text class="range-label">选择第几条数据(1-12之间)</text>
<view class="freight-picker" style="margin-top:10rpx;">
<picker mode="selector" :range="positionOptions" @change="onPositionChange"
:value="selectedPositionIndex">
<view class="picker-content">
{{ positionOptions[selectedPositionIndex] || '请选择位置' }}
<text class="arrow"></text>
</view>
</picker>
</view>
</view>
<text v-if="current1 === 2">以最近售出的<text class="highlight-text">总价</text>为参照<text
style="color:red">[不含运费]</text></text>
</view>
</view>
</view>
<!-- 加减幅度模块 -->
<view class="u-demo-block">
<view class="section-header">
<text class="section-title">运费</text>
</view>
<!-- 数字输入框双向绑定value3设置取值范围、步长和小数位数 -->
<view class="number-control-wrapper">
<text class="number-control-btn minus-btn" @click="decreaseValue3">-</text>
<input type="digit" v-model="value3" class="custom-input-box" @blur="validateValue3"
:disabled="false" />
<text class="number-control-btn plus-btn" @click="increaseValue3">+</text>
</view>
<!-- 最低值模块 -->
<view class="section-header">
<text class="section-title">最低书价(不含运费)</text>
</view>
<!-- 数字输入框双向绑定value4设置取值范围、步长和小数位数 -->
<view class="number-control-wrapper">
<text class="number-control-btn minus-btn" @click="decreaseValue4">-</text>
<input type="digit" v-model="value4" class="custom-input-box" @blur="validateValue4"
:disabled="false" />
<text class="number-control-btn plus-btn" @click="increaseValue4">+</text>
</view>
</view>
<!-- 价格排序方式选择模块 -->
<!-- 已删除价格排序方式下拉框,默认总价从低到高[含运费] -->
<!-- 品相筛选模块 -->
<view class="u-demo-block" style="margin-top:40rpx">
<view class="section-header">
<text class="section-title">品相筛选</text>
<text class="section-subtitle">根据自己偏好选择</text>
</view>
<view class="freight-picker">
<!-- 选择器组件选择品相range绑定品相选项列表选择变化时触发onConditionCode方法value绑定selectConditionCodeIndex -->
<picker mode="selector" :range="conditionCode" @change="onConditionCode"
:value="selectConditionCodeIndex">
<view class="picker-content">
{{ conditionCode[selectConditionCodeIndex] || '请选择品相' }}
<text class="arrow"></text>
</view>
</picker>
</view>
</view>
</view>
</template>
<script>
import request from '@/utils/request.js';
import {
mapState,
mapMutations
} from 'vuex'
// Vuex 模块拆分后使用命名空间访问
export default {
computed: {
...mapState('price', ['priceMode', 'priceType'])
},
watch: {
value1: {
handler(newVal) {
this.saveBlockedShops();
},
immediate: false
}
},
// 添加创建时的初始化检查
created() {
console.log('组件创建 - 检查是否有初始化标记');
// 检查是否是第一次启动应用
const hasInitialized = uni.getStorageSync('app_initialized');
if (!hasInitialized) {
console.log('首次启动应用 - 设置默认值');
// 第一次启动应用,设置默认值
uni.setStorageSync('current1', 1); // 均价
uni.setStorageSync('current2', 1); // 总价
uni.setStorageSync('selectedSortIndex', 1); // 价格排序方式默认为总价从低到高
uni.setStorageSync('sortType', '7'); // 设置sortType为7
uni.setStorageSync('app_initialized', true); // 标记已初始化
} else {
// 即使不是首次启动,也确保有默认值
if (!uni.getStorageSync('sortType')) {
uni.setStorageSync('sortType', '7');
}
if (!uni.getStorageSync('selectedSortIndex')) {
uni.setStorageSync('selectedSortIndex', 1);
}
}
// 读取记住密码设置
this.rememberPassword = uni.getStorageSync('rememberPassword') === true;
console.log('初始化时记住密码设置为:', this.rememberPassword);
// 加载账号信息
this.loadAccounts();
// 如果设置了记住密码,则填充用户名和密码
if (this.rememberPassword) {
const savedUsername = uni.getStorageSync('KongfzUserName');
const savedPassword = uni.getStorageSync('KongfzPassword');
console.log('读取到保存的用户名:', savedUsername);
console.log('是否有保存的密码:', savedPassword ? '是' : '否');
this.username = savedUsername || '';
this.password = savedPassword || '';
}
// 监听账号切换事件
uni.$on('accountSwitched', this.handleAccountSwitched);
},
// 组件销毁时移除事件监听
beforeDestroy() {
uni.$off('accountSwitched', this.handleAccountSwitched);
},
data() {
return {
username: '', // 添加用户名字段
password: '', // 添加密码字段
isLogging: false,
isLoading: false, // 登录加载状态
isLoggedIn: false, // 登录状态
userInfo: null, // 添加用户信息字段
conditionValue: '', // 存储品相对应的数值范围
sortType: '', //存储价格类型
shippingTemplate: 1,
barcodes: [],
value1: '', // 屏蔽店铺列表
current1: 1, // 控制价格模式第一个选项卡的当前选中状态
averageRange: 3, // 当价格模式为"均价"时,用于计算平均值的价格数量范围
current2: 1, // 控制价格模式相关的第二个选项卡的当前选中状态
list: ['最低价', '均价'], // 价格模式的选项列表
list2: ['书价', '总价'], // 与价格模式相关的另一组选项列表
value3: 0, // 加减幅度的数值
value4: 0.1, // 最低值的数值
positionOptions: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'], // 位置选项列表
selectedPositionIndex: 0, // 选择的位置索引默认为0第一条数据
freightTemplateId: null, // 选中的运费模板ID
freightTemplateList: [ // 运费模板数据列表
{
id: 1,
templateName: '模板一'
},
{
id: 2,
templateName: '模板二'
},
{
id: 3,
templateName: '模板三'
}
],
conditionCode: ['全部品相', '全新', '古旧书', '九五品以上', '九品以上', '八五品以上', '八品以上'], // 品相筛选的选项列表
freightTemplateIndex: 0, // 运费模板选择器的当前索引
selectedFreightTemplate: {}, // 存储当前选中的运费模板对象
sortOptions: ['书价从低到高', '总价从低到高[含运费]'], // 价格排序方式的选项列表
selectedSortIndex: 1, // 价格排序方式选择器的当前索引
selectConditionCodeIndex: 0, // 品相筛选选择器的当前索引
selectShopTypeIndex: 0, // 本店分类选择器的当前索引
selectedGoodsNoIndex: 0,
searchThenTakePhoto: false, // "搜索完成后开始拍照"功能的开关状态
takePhotoNextSubmit: false, // "拍照下一步自动提交"功能的开关状态
submitSound: false, // "提交成功提示音"功能的开关状态
scanGunMode: false, // "扫码枪模式"功能的开关状态
isbnCheck: false, // 用于控制"通过isbn检测商品是否存在"开关的状态
articleNumberCheck: false, // 用于控制"通过货号检测商品是否存在"开关的状态
goodsNoOptions: ['手动输入或者扫码', '初始货号尾数数字自增', '同isbn码一致'],
// 参考价小数位选项
decimalOptions: ['一位小数', '两位小数', '三位小数'],
selectedDecimalIndex: 0,
// 商品列表价格展示选项
priceDisplayOptions: ['显示价格', '不显示价格'],
priceDisplayIndex: 0,
// 商品列表展示选项
displayModeOptions: ['详细展示', '简洁展示'],
displayModeIndex: 0,
rememberPassword: false,
accounts: [], // 存储多个账号信息,初始化为空,从本地存储加载
showAccountPopup: false, // 控制添加账号弹窗的显示
newAccount: { // 新增账号的临时数据
username: '',
password: ''
},
currentAccountIndex: 0, // 当前使用的账号索引
maxLoginAttempts: 3, // 最大自动登录尝试次数
loginAttemptCount: 0 // 当前尝试登录次数
}
},
onShow() {
// 调试:打印初始状态
console.log('=== 页面显示 - 初始状态 ===');
console.log('存储中的 current1:', uni.getStorageSync('current1'));
console.log('存储中的 current2:', uni.getStorageSync('current2'));
// 检查是否已登录
const cookies = uni.getStorageSync('UserInfoCookies');
const savedUsername = uni.getStorageSync('KongfzUserName');
const savedPassword = uni.getStorageSync('KongfzPassword');
// 初始化登录状态为 false
this.isLoggedIn = false;
if (cookies && savedUsername) {
// 如果有保存的登录凭证先临时设置登录状态为true
this.isLoggedIn = true;
this.username = savedUsername;
// 获取用户信息并验证cookie
this.getUserInfo(cookies);
// 失效后尝试自动登录
// this.verifyCookieValid(cookies, savedUsername, savedPassword);
}
// } else if (savedUsername && savedPassword) {
// // 有账号密码但没有cookie尝试自动登录
// console.log('发现账号密码但cookie丢失尝试自动登录');
// this.autoLogin(savedUsername, savedPassword);
// }
// 从本地存储中读取之前保存的值 - 直接加载实际存储的值
this.value1 = uni.getStorageSync('blockedShops') || '';
// 添加安全的数据获取函数
const getSafeNumber = (key, defaultValue, isFloat = false) => {
const value = uni.getStorageSync(key);
if (value === '' || value === null || value === undefined) {
return defaultValue;
}
try {
return isFloat ? parseFloat(value) : parseInt(value);
} catch (e) {
console.error(`转换${key}出错:`, e);
return defaultValue;
}
};
// 安全读取所有设置
this.current1 = getSafeNumber('current1', 1);
this.current2 = getSafeNumber('current2', 1);
this.averageRange = getSafeNumber('averageRange', 3);
this.value3 = getSafeNumber('value3', 0, true);
this.value4 = getSafeNumber('value4', 0.1, true);
this.selectedSortIndex = getSafeNumber('selectedSortIndex', 1);
this.selectConditionCodeIndex = getSafeNumber('selectConditionCodeIndex', 0);
this.selectedPositionIndex = getSafeNumber('selectedPositionIndex', 0);
// 调试: 打印加载后的状态
console.log('=== 页面加载完成 - 当前状态 ===');
console.log('current1:', this.current1, '- 模式:', this.list[this.current1]);
console.log('current2:', this.current2, '- 类型:', this.list2[this.current2]);
// 读取其他设置
this.freightTemplateIndex = getSafeNumber('freightTemplateIndex', 0);
this.selectShopTypeIndex = getSafeNumber('selectShopTypeIndex', 0);
this.selectedGoodsNoIndex = getSafeNumber('selectedGoodsNoIndex', 0);
this.selectedDecimalIndex = getSafeNumber('selectedDecimalIndex', 0);
this.priceDisplayIndex = getSafeNumber('priceDisplayIndex', 0);
this.displayModeIndex = getSafeNumber('displayModeIndex', 0);
// 同步当前值到Vuex store
this.updatePriceMode(this.current1);
this.updatePriceType(this.current2);
this.updateAverageRange(this.averageRange);
this.updateSelectedPosition(parseInt(this.selectedPositionIndex));
this.updateFreight(this.value3);
this.updateMinValue(this.value4);
// 确保品相值也被正确设置
const selectedCondition = this.conditionCode[this.selectConditionCodeIndex];
switch (selectedCondition) {
case '九五品以上':
this.conditionValue = '95~';
break;
case '全新':
this.conditionValue = '100~';
break;
case '古旧书':
this.conditionValue = '~99';
break;
case '九品以上':
this.conditionValue = '90~';
break;
case '八五品以上':
this.conditionValue = '85~';
break;
case '八品以上':
this.conditionValue = '80~';
break;
case '七品以上':
this.conditionValue = '70~';
break;
default:
this.conditionValue = '';
}
uni.setStorageSync('conditionValue', this.conditionValue);
},
methods: {
...mapMutations('price', ['updatePriceMode', 'updatePriceType', 'updateAverageRange',
'updateFreight', 'updateMinValue'
]),
...mapMutations('warehouse', ['updateSelectedPosition']),
// 加载保存的账号信息
loadAccounts() {
try {
const savedAccounts = uni.getStorageSync('accounts');
if (savedAccounts) {
this.accounts = JSON.parse(savedAccounts);
console.log('已加载账号列表,共', this.accounts.length, '个账号');
// 获取当前使用的账号索引
const currentIndex = uni.getStorageSync('currentAccountIndex');
this.currentAccountIndex = currentIndex !== '' ? parseInt(currentIndex) : 0;
// 确保有一个账号被标记为活跃
let hasActive = false;
this.accounts.forEach((acc, idx) => {
if (acc.isActive) {
hasActive = true;
this.currentAccountIndex = idx;
}
});
// 如果没有活跃账号但有账号,则设置第一个为活跃
if (!hasActive && this.accounts.length > 0) {
this.accounts[0].isActive = true;
this.currentAccountIndex = 0;
uni.setStorageSync('accounts', JSON.stringify(this.accounts));
}
// 如果有活跃账号,设置当前用户名和密码
if (this.accounts.length > 0 && this.accounts[this.currentAccountIndex]) {
this.username = this.accounts[this.currentAccountIndex].username;
this.password = this.accounts[this.currentAccountIndex].password;
}
} else {
// 如果没有保存的账号,创建空数组
this.accounts = [];
console.log('没有保存的账号,初始化为空列表');
// 如果有保存的单一账号密码,迁移它
const savedUsername = uni.getStorageSync('KongfzUserName');
const savedPassword = uni.getStorageSync('KongfzPassword');
if (savedUsername && savedPassword) {
console.log('发现已保存的单一账号,迁移至账号列表');
this.accounts.push({
username: savedUsername,
password: savedPassword,
isActive: true
});
this.currentAccountIndex = 0;
uni.setStorageSync('accounts', JSON.stringify(this.accounts));
}
}
} catch (error) {
console.error('加载账号信息失败:', error);
this.accounts = [];
}
},
// 监听value1变化并保存到本地存储
saveBlockedShops() {
uni.setStorageSync('blockedShops', this.value1);
},
// 登录孔网
async login() {
// 防止重复提交
if (this.isLogging) return
this.isLogging = true
this.isLoading = true // 显示加载动画
// 使用当前选择的账号
let loginUsername = this.username
let loginPassword = this.password
// 如果账号列表中有账号,使用当前活跃账号
// if (this.accounts.length > 0) {
// const activeAccount = this.accounts.find(acc => acc.isActive);
// if (activeAccount) {
// loginUsername = activeAccount.username;
// loginPassword = activeAccount.password;
// console.log("使用账号列表中的活跃账号:", loginUsername);
// }
// }
try {
const result = await this.getCookies(loginUsername, loginPassword);
console.log("result", result)
// 检查是否需要手机验证登录
if (result.responseData && result.responseData.extInfo &&
result.responseData.extInfo.action === "redirect" &&
result.responseData.extInfo.uri.includes("请使用手机号验证登录")) {
// 尝试切换到下一个账号
if (await this.switchToNextAccount("该账号需要手机验证,尝试下一个账号")) {
this.isLogging = false;
this.isLoading = false;
return this.login(); // 重新尝试登录
}
uni.showToast({
title: '无法登录,所有账号都需要手机验证',
icon: 'none',
duration: 2500
});
return;
}
// 检查其他重定向情况
if (result.responseData && result.responseData.extInfo &&
result.responseData.extInfo.action === "redirect") {
// 尝试切换到下一个账号
if (await this.switchToNextAccount("账号登录异常,尝试下一个账号")) {
this.isLogging = false;
this.isLoading = false;
return this.login(); // 重新尝试登录
}
uni.showToast({
title: '无法登录,请检查账号或添加新账号',
icon: 'none',
duration: 2500
});
return;
}
// 检查常见错误情况
console.log("result.responseData.errType", result.responseData.errType)
// 处理错误情况
if (result.responseData.errType === "102" ||
[102, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009].includes(result.responseData.errCode)) {
// 准备错误消息
let errorMsg;
switch (result.responseData.errCode) {
case 102: errorMsg = '用户名不能为空'; break;
case 1000: errorMsg = '授权码错误或已过期'; break;
case 1001: errorMsg = '用户不存在'; break;
case 1009: errorMsg = '调用次数已达上限'; break;
default: errorMsg = result.responseData.errInfo || '账号登录异常';
}
// 尝试切换到下一个账号
if (await this.switchToNextAccount(`${errorMsg},尝试下一个账号`)) {
this.isLogging = false;
this.isLoading = false;
return this.login(); // 重新尝试登录
}
// 如果无法切换账号,显示错误
uni.showToast({
title: `${errorMsg},所有账号都无法使用`,
icon: 'none',
duration: 2500
});
return;
}
// 登录成功,保存 Cookie 到本地存储
if (result.cookies && result.cookies.PHPSESSID) {
// 保存cookies
uni.setStorageSync('cookies', result.cookies.PHPSESSID);
uni.setStorageSync('UserInfoCookies', result.cookies.PHPSESSID);
// 总是保存用户名(当前活跃账号的用户名)
uni.setStorageSync('KongfzUserName', loginUsername);
// 先保存记住密码设置
console.log('保存记住密码设置:', this.rememberPassword);
uni.setStorageSync('rememberPassword', this.rememberPassword);
if (this.rememberPassword) {
// 如果选择记住密码,明确保存密码
console.log('保存密码:', loginPassword);
uni.setStorageSync('KongfzPassword', loginPassword);
} else {
// 如果不记住密码,确保移除保存的密码
console.log('移除已保存的密码');
uni.removeStorageSync('KongfzPassword');
}
console.log('成功保存cookies:', result.cookies.PHPSESSID);
// 重置登录尝试计数
this.loginAttemptCount = 0;
// 获取用户信息
await this.getUserInfo(result.cookies.PHPSESSID);
// 更新登录状态
this.isLoggedIn = true;
// 显示成功提示
uni.showToast({
title: '登录成功',
icon: 'success',
duration: 2000
});
} else {
// 尝试切换到下一个账号
if (await this.switchToNextAccount('登录失败未获取到cookies尝试下一个账号')) {
this.isLogging = false;
this.isLoading = false;
return this.login(); // 重新尝试登录
}
uni.showToast({
title: '登录失败所有账号都无法获取cookies',
icon: 'none',
duration: 2500
});
}
} catch (error) {
console.error('登录出错:', error);
// 尝试切换到下一个账号
if (await this.switchToNextAccount('登录出错,尝试下一个账号')) {
this.isLogging = false;
this.isLoading = false;
return this.login(); // 重新尝试登录
}
uni.showToast({
title: '所有账号登录失败,请检查网络',
icon: 'none'
});
} finally {
this.isLogging = false;
this.isLoading = false; // 隐藏加载动画
}
},
// 切换到下一个可用账号
async switchToNextAccount(message) {
if (this.accounts.length <= 1) {
console.log('没有备用账号可用');
return false;
}
// 增加尝试次数
this.loginAttemptCount++;
// 检查是否超过最大尝试次数
if (this.loginAttemptCount > this.maxLoginAttempts) {
console.log('超过最大尝试登录次数');
uni.showToast({
title: '已尝试所有账号,请检查账号状态',
icon: 'none',
duration: 2500
});
this.loginAttemptCount = 0;
return false;
}
// 获取当前账号索引
let currentIndex = this.accounts.findIndex(acc => acc.isActive);
if (currentIndex === -1) currentIndex = 0;
// 找到下一个账号索引
let nextIndex = (currentIndex + 1) % this.accounts.length;
// 确保不会无限循环
if (nextIndex === currentIndex) {
return false;
}
// 切换到下一个账号
console.log(`${message},从账号 ${this.accounts[currentIndex].username} 切换到 ${this.accounts[nextIndex].username}`);
this.accounts.forEach((acc, idx) => {
acc.isActive = (idx === nextIndex);
});
this.currentAccountIndex = nextIndex;
this.username = this.accounts[nextIndex].username;
this.password = this.accounts[nextIndex].password;
// 保存更新后的账号列表
uni.setStorageSync('accounts', JSON.stringify(this.accounts));
uni.setStorageSync('currentAccountIndex', nextIndex);
uni.showToast({
title: `${message.substring(0, 10)}...,切换到备用账号`,
icon: 'none',
duration: 1500
});
return true;
},
// 获取用户信息
async getUserInfo(cookies) {
try {
console.log("开始获取用户信息...")
// 使用API包装函数获取用户信息
const data = await this.apiRequestWithRetry('https://search.kongfz.com/common-web/v1/api/userInfo', {
header: { 'Cookie': `PHPSESSID=${cookies}` }
});
console.log("用户数据",data)
if (data && data.status === 1) {
this.userInfo = data.data;
// 保存用户信息到本地存储
uni.setStorageSync('userInfo', data.data);
this.isLoggedIn = true; // 更新登录状态
} else {
throw new Error(data.message || '获取用户信息失败');
}
} catch (error) {
console.error('获取用户信息失败:', error);
// 如果获取用户信息失败可能是cookie失效
this.isLoggedIn = false;
// 尝试重新登录
if (this.accounts.length > 0) {
const activeAccount = this.accounts.find(acc => acc.isActive);
if (activeAccount) {
console.log('Cookie无效尝试重新登录');
await this.login();
}
} else {
uni.showToast({
title: '获取用户信息失败,请重新登录',
icon: 'none'
});
}
}
},
// 孔网API请求包装函数支持自动重试和账号切换
async apiRequestWithRetry(url, options = {}, maxRetries = 2) {
let retryCount = 0;
let lastError = null;
while (retryCount <= maxRetries) {
try {
// 获取当前cookie
const cookies = uni.getStorageSync('UserInfoCookies');
if (!cookies) {
throw new Error('未登录,请先登录账号');
}
// 默认添加Cookie头
const headers = {
'Cookie': `PHPSESSID=${cookies}`,
...(options.header || {})
};
// 发起请求
const [err, res] = await uni.request({
url,
method: options.method || 'GET',
data: options.data,
header: headers
});
if (err) {
throw new Error('请求失败: ' + (err.errMsg || '未知错误'));
}
// 检查是否有错误码如1000、1009等
if (res.data && (res.data.errCode || res.data.errType)) {
// 特定错误码表示cookie失效或权限问题
const errorCode = res.data.errCode || 0;
const errorType = res.data.errType || '';
if ([102, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009].includes(errorCode) ||
errorType === '102') {
console.log(`API返回错误: 代码=${errorCode}, 类型=${errorType}, 信息=${res.data.errInfo || '无'}`);
// 尝试切换账号
if (await this.switchToNextAccount('API调用错误尝试切换账号')) {
console.log('切换账号成功,重新登录中...');
// 重新登录
await this.login();
// 登录成功后重试
retryCount++;
continue;
} else {
// 无法切换账号,抛出错误
throw new Error(res.data.errInfo || `API调用错误 ${errorCode}`);
}
}
}
// 成功响应
return res.data;
} catch (error) {
console.error(`API请求失败(第${retryCount + 1}次尝试):`, error);
lastError = error;
retryCount++;
// 最后一次尝试失败,抛出异常
if (retryCount > maxRetries) {
throw error;
}
// 等待一段时间再重试
await new Promise(resolve => setTimeout(resolve, 500));
}
}
// 不应该执行到这里,但为保险起见
throw lastError || new Error('请求失败,请重试');
},
// 退出登录
handleLogout() {
uni.showModal({
title: '提示',
content: '确定要退出登录吗?',
success: (res) => {
if (res.confirm) {
// 清除登录状态和用户信息
this.isLoggedIn = false;
// 获取当前活跃账号
const activeAccount = this.accounts.find(acc => acc.isActive);
if (activeAccount) {
// 如果有活跃账号,填充用户名和密码
this.username = activeAccount.username;
this.password = activeAccount.password;
} else if (this.rememberPassword) {
// 如果记住密码但没有活跃账号,使用存储的用户名和密码
const savedUsername = uni.getStorageSync('KongfzUserName');
const savedPassword = uni.getStorageSync('KongfzPassword');
this.username = savedUsername || '';
this.password = savedPassword || '';
} else {
// 如果不记住密码,清空密码字段
this.password = '';
}
// 清除用户信息和cookies
this.userInfo = null;
uni.removeStorageSync('UserInfoCookies');
uni.removeStorageSync('cookies');
uni.showToast({
title: '已退出登录',
icon: 'success'
});
}
}
});
},
// 处理价格模式第一个选项卡变化的方法更新current1的值
change1(index) {
console.log('修改价格模式前:', this.current1);
this.current1 = index;
// 强制确保保存为数字
uni.setStorageSync('current1', index);
console.log('已保存价格模式:', index);
this.updatePriceMode(index);
console.log('价格模式已更改为:', this.list[index], '(值:', index, ')');
// 立即从存储中读取并验证
setTimeout(() => {
const storedValue = uni.getStorageSync('current1');
console.log('存储中的值现在是:', storedValue);
}, 100);
},
// 处理价格模式第二个选项卡变化的方法更新current2的值
change2(index) {
console.log('修改价格类型前:', this.current2);
this.current2 = index;
// 强制确保保存为数字
uni.setStorageSync('current2', index);
console.log('已保存价格类型:', index);
this.updatePriceType(index);
console.log('价格类型已更改为:', this.list2[index], '(值:', index, ')');
// 立即从存储中读取并验证
setTimeout(() => {
const storedValue = uni.getStorageSync('current2');
console.log('存储中的值现在是:', storedValue);
}, 100);
},
// 处理位置选择变化的方法更新selectedPositionIndex的值
onPositionChange(e) {
this.selectedPositionIndex = e.detail.value;
console.log("选择第几条数据", this.selectedPositionIndex)
uni.setStorageSync('selectedPositionIndex', this.selectedPositionIndex);
this.updateSelectedPosition(parseInt(this.selectedPositionIndex));
},
// 处理品相变化
onConditionCode(e) {
this.selectConditionCodeIndex = e.detail.value;
uni.setStorageSync('selectConditionCodeIndex', this.selectConditionCodeIndex);
// 根据选择的品相设置对应的数值范围
const selectedCondition = this.conditionCode[e.detail.value];
switch (selectedCondition) {
case '九五品以上':
this.conditionValue = '95~';
break;
case '全新':
this.conditionValue = '100~';
break;
case '古旧书':
this.conditionValue = '~99';
break;
case '九品以上':
this.conditionValue = '90~';
break;
case '八五品以上':
this.conditionValue = '85~';
break;
case '八品以上':
this.conditionValue = '80~';
break;
case '七品以上':
this.conditionValue = '70~';
break;
default:
this.conditionValue = '';
}
console.log("selectedCondition", this.conditionValue)
uni.setStorageSync('conditionValue', this.conditionValue);
},
onShopType(e) {
this.selectShopTypeIndex = e.detail.value;
uni.setStorageSync('selectShopTypeIndex', this.selectShopTypeIndex);
},
onGoodsNoChange(e) {
this.selectedGoodsNoIndex = e.detail.value;
uni.setStorageSync('selectedGoodsNoIndex', this.selectedGoodsNoIndex);
},
handleDecimalChange(e) {
this.selectedDecimalIndex = e.detail.value;
uni.setStorageSync('selectedDecimalIndex', this.selectedDecimalIndex);
console.log('参考价小数位选择变更为:', this.decimalOptions[this.selectedDecimalIndex]);
},
handlePriceDisplayChange(e) {
this.priceDisplayIndex = e.detail.value;
uni.setStorageSync('priceDisplayIndex', this.priceDisplayIndex);
console.log('商品列表价格展示选择变更为:', this.priceDisplayOptions[this.priceDisplayIndex]);
},
handleDisplayModeChange(e) {
this.displayModeIndex = e.detail.value;
uni.setStorageSync('displayModeIndex', this.displayModeIndex);
console.log('商品列表展示选择变更为:', this.displayModeOptions[this.displayModeIndex]);
},
// 运费和最低值相关方法
validateValue3() {
let val = parseFloat(this.value3);
if (isNaN(val)) {
this.value3 = 0;
} else if (val > 99) {
this.value3 = 99;
} else if (val < -99) {
this.value3 = -99;
} else {
this.value3 = parseFloat(val.toFixed(2));
}
this.updateFreight(this.value3);
console.log("123", this.value3)
uni.setStorageSync('value3', this.value3);
},
validateValue4() {
let val = parseFloat(this.value4);
if (isNaN(val)) {
this.value4 = 0.1;
} else if (val > 999) {
this.value4 = 999;
} else if (val < 0.01) {
this.value4 = 0.01;
} else {
this.value4 = parseFloat(val.toFixed(2));
}
this.updateMinValue(this.value4);
uni.setStorageSync('value4', this.value4);
},
// 增加运费值的方法
increaseValue3() {
if (parseFloat(this.value3) < 99) {
this.value3 = parseFloat((parseFloat(this.value3) + 1).toFixed(2));
uni.setStorageSync('value3', this.value3);
console.log("增加运费值", this.value3)
// 同步到Vuex store
this.updateFreight(this.value3);
}
},
// 减少运费值的方法
decreaseValue3() {
if (parseFloat(this.value3) > -99) {
this.value3 = parseFloat((parseFloat(this.value3) - 1).toFixed(2));
uni.setStorageSync('value3', this.value3);
// 同步到Vuex store
this.updateFreight(this.value3);
}
},
// 增加最低值的方法
increaseValue4() {
if (parseFloat(this.value4) < 999) {
this.value4 = parseFloat((parseFloat(this.value4) + 0.01).toFixed(2));
uni.setStorageSync('value4', this.value4);
// 同步到Vuex store
this.updateMinValue(this.value4);
}
},
// 减少最低值的方法
decreaseValue4() {
if (parseFloat(this.value4) > 0.01) {
this.value4 = parseFloat((parseFloat(this.value4) - 0.01).toFixed(2));
uni.setStorageSync('value4', this.value4);
// 同步到Vuex store
this.updateMinValue(this.value4);
}
},
// 增加averageRange值的方法
increaseRange() {
if (this.averageRange < 12) {
this.averageRange++;
this.updateAverageRange(this.averageRange);
uni.setStorageSync('averageRange', this.averageRange);
}
},
// 减少averageRange值的方法
decreaseRange() {
if (this.averageRange > 2) {
this.averageRange--;
this.updateAverageRange(this.averageRange);
uni.setStorageSync('averageRange', this.averageRange);
}
},
// 纯浏览器端 JavaScript 实现
async getCookies(username, password) {
try {
// 第一步先发送一个GET请求获取初始会话Cookie
const initResponse = await this.uniRequestPromise({
url: 'https://login.kongfz.com/Pc/Login/account',
method: 'GET'
});
// 提取初始响应中的Cookie
const initCookies = this.extractCookiesFromHeaders(initResponse.header);
// 第二步:发送登录请求,携带用户名和密码
const loginData = {
loginName: username,
loginPass: password
};
const loginResponse = await this.uniRequestPromise({
url: 'https://login.kongfz.com/Pc/Login/account',
method: 'POST',
data: loginData,
header: {
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': this.formatCookieHeader(initCookies)
}
});
// 提取登录响应中的Cookie
const loginCookies = this.extractCookiesFromHeaders(loginResponse.header);
// 合并所有Cookie
const allCookies = {
...initCookies,
...loginCookies
};
// 检查登录是否成功(根据实际返回判断)
const isLoginSuccess = this.checkLoginSuccess(loginResponse.data);
return {
success: isLoginSuccess,
cookies: allCookies,
responseData: loginResponse.data // 包含服务器返回的原始数据
};
} catch (error) {
console.error('登录请求失败:', error);
return {
success: false,
error: error.message || '登录请求发生错误'
};
}
},
/**
* 将 uni.request 转换为 Promise 形式
*/
uniRequestPromise(options) {
return new Promise((resolve, reject) => {
uni.request({
...options,
success: (res) => resolve(res),
fail: (err) => reject(err)
});
});
},
/**
* 从响应头中提取 Cookies
*/
extractCookiesFromHeaders(headers) {
const cookies = {};
const cookieHeaders = headers['Set-Cookie'] || headers['set-cookie'];
if (!cookieHeaders) return cookies;
// 处理可能是数组或字符串的 Cookie 头
const cookieList = Array.isArray(cookieHeaders) ?
cookieHeaders : [cookieHeaders];
cookieList.forEach(cookieStr => {
// 提取 cookie 名值对(忽略路径、过期时间等属性)
const cookieParts = cookieStr.split(';')[0].split('=');
if (cookieParts.length >= 2) {
cookies[cookieParts[0].trim()] = cookieParts[1].trim();
}
});
return cookies;
},
/**
* 将 Cookie 对象格式化为请求头字符串
*/
formatCookieHeader(cookies) {
return Object.entries(cookies)
.map(([key, value]) => `${key}=${value}`)
.join('; ');
},
/**
* 检查登录是否成功(根据实际接口返回调整)
*/
checkLoginSuccess(responseData) {
// 检查是否需要手机验证登录
if (responseData.extInfo && responseData.extInfo.action === "redirect" &&
responseData.extInfo.uri.includes("请使用手机号验证登录")) {
return false;
}
// 这里需要根据实际返回的数据结构判断登录是否成功
// 示例:假设返回包含 success: true 或 code: 200
if (responseData.success === true || responseData.code === 200) {
return true;
}
// 默认返回 false
return false;
},
// 处理登录按钮点击事件
click() {
if (!this.username || !this.password) {
uni.showToast({
title: '请输入账号和密码',
icon: 'none',
duration: 2500
});
return;
}
// TODO: 实现登录逻辑
console.log('登录请求,用户名:', this.username, '密码:', this.password);
// 这里可以调用登录API
},
// 新增方法:自动登录
async autoLogin(username, password) {
try {
console.log('尝试自动登录...');
this.isLogging = true;
const result = await this.getCookies(username, password);
if (result.cookies && result.cookies.PHPSESSID) {
// 保存cookies
uni.setStorageSync('cookies', result.cookies.PHPSESSID);
uni.setStorageSync('UserInfoCookies', result.cookies.PHPSESSID);
// 获取用户信息
await this.getUserInfo(result.cookies.PHPSESSID);
// 更新登录状态
this.isLoggedIn = true;
this.username = username;
console.log('自动登录成功');
return true; // 返回登录成功
} else {
console.error('自动登录失败未获取到有效cookie');
return false;
}
} catch (error) {
console.error('自动登录失败:', error);
return false;
} finally {
this.isLogging = false;
}
},
// 新增方法验证cookie有效性
async verifyCookieValid(cookie, username, password) {
try {
// 使用cookie发送一个简单请求验证有效性
const [err, res] = await uni.request({
url: 'https://search.kongfz.com/common-web/v1/api/userInfo',
method: 'GET',
header: {
'Cookie': `PHPSESSID=${cookie}`
}
});
// 如果请求成功且返回正常状态cookie有效
if (!err && res.data && res.data.status === 1) {
console.log('Cookie验证有效');
this.isLoggedIn = true; // 确保设置登录状态
return true;
}
// cookie无效尝试重新登录
console.log('Cookie已失效尝试重新登录');
if (username && password) {
const loginSuccess = await this.autoLogin(username, password);
return loginSuccess; // 返回自动登录结果
}
return false;
} catch (error) {
console.error('验证cookie有效性出错:', error);
return false;
}
},
// 处理记住密码选项变化
handleRememberPasswordChange(e) {
this.rememberPassword = e.detail.value.length > 0;
console.log('记住密码设置变更为:', this.rememberPassword);
// 保存设置到本地存储
uni.setStorageSync('rememberPassword', this.rememberPassword);
},
// 显示添加账号弹窗
showAddAccount() {
this.newAccount = { username: '', password: '' }; // 清空新增账号输入框
this.$refs.accountPopup.open(); // 使用ref打开弹窗
console.log('显示添加账号弹窗');
},
// 关闭弹窗
closePopup() {
this.$refs.accountPopup.close();
},
// 添加新账号
async addAccount() {
if (!this.newAccount.username || !this.newAccount.password) {
uni.showToast({
title: '账号或密码不能为空',
icon: 'none'
});
return;
}
// 检查账号是否已存在
const isDuplicate = this.accounts.some(account => account.username === this.newAccount.username);
if (isDuplicate) {
uni.showModal({
title: '账号已存在',
content: '该账号已添加,不可重复添加',
showCancel: false
});
return;
}
// 显示加载状态
uni.showLoading({
title: '正在验证账号...',
mask: true
});
try {
// 尝试使用账号密码登录验证
const result = await this.getCookies(this.newAccount.username, this.newAccount.password);
// 隐藏加载
uni.hideLoading();
// 检查是否需要手机验证登录
if (result.responseData && result.responseData.extInfo &&
result.responseData.extInfo.action === "redirect" &&
result.responseData.extInfo.uri && result.responseData.extInfo.uri.includes("请使用手机号验证登录")) {
uni.showModal({
title: '账号需要验证',
content: '该账号需要手机验证,请添加其他账号',
showCancel: false
});
return;
}
// 检查其他重定向情况
if (result.responseData && result.responseData.extInfo &&
result.responseData.extInfo.action === "redirect") {
uni.showModal({
title: '账号异常',
content: '账号登录异常,请检查账号后重试',
showCancel: false
});
return;
}
// 检查常见错误情况
if (result.responseData && (result.responseData.errType === "102" ||
[102, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1007, 1008, 1009].includes(result.responseData.errCode))) {
// 准备错误消息
let errorMsg;
switch (result.responseData.errCode) {
case 102: errorMsg = '用户名不能为空'; break;
case 1000: errorMsg = '授权码错误或已过期'; break;
case 1001: errorMsg = '用户不存在'; break;
case 1009: errorMsg = '调用次数已达上限'; break;
default: errorMsg = result.responseData.errInfo || '账号登录异常';
}
uni.showModal({
title: '账号验证失败',
content: errorMsg,
showCancel: false
});
return;
}
// 验证成功获取到了有效cookies添加账号
if (result.cookies && result.cookies.PHPSESSID) {
this.accounts.push({
username: this.newAccount.username,
password: this.newAccount.password,
isActive: false
});
this.$refs.accountPopup.close(); // 关闭弹窗
uni.setStorageSync('accounts', JSON.stringify(this.accounts)); // 保存账号列表
uni.showToast({
title: '账号验证成功并已添加',
icon: 'success'
});
} else {
uni.showModal({
title: '账号验证失败',
content: '无法获取有效登录信息,请检查账号密码',
showCancel: false
});
}
} catch (error) {
uni.hideLoading();
console.error('验证账号时出错:', error);
uni.showModal({
title: '验证失败',
content: '网络异常或服务器错误,请稍后重试',
showCancel: false
});
}
},
// 设置账号为当前使用
async setAsActive(index) {
// 显示加载状态
uni.showLoading({
title: '正在切换账号...',
mask: true
});
try {
// 获取要切换的账号信息
const targetAccount = this.accounts[index];
// 清除原有的cookie
uni.removeStorageSync('cookies');
uni.removeStorageSync('UserInfoCookies');
// 尝试使用账号密码登录获取新cookie
const result = await this.getCookies(targetAccount.username, targetAccount.password);
// 检查是否登录成功
if (result.cookies && result.cookies.PHPSESSID) {
// 更新账号状态
this.accounts.forEach(acc => acc.isActive = false);
this.accounts[index].isActive = true;
this.currentAccountIndex = index;
// 保存cookie到本地存储
uni.setStorageSync('cookies', result.cookies.PHPSESSID);
uni.setStorageSync('UserInfoCookies', result.cookies.PHPSESSID);
uni.setStorageSync('KongfzUserName', targetAccount.username);
// 如果设置了记住密码,则保存密码
if (this.rememberPassword) {
uni.setStorageSync('KongfzPassword', targetAccount.password);
}
// 保存更新后的账号列表
uni.setStorageSync('accounts', JSON.stringify(this.accounts));
uni.setStorageSync('currentAccountIndex', index);
// 获取用户信息
await this.getUserInfo(result.cookies.PHPSESSID);
// 更新登录状态和当前用户名
this.isLoggedIn = true;
this.username = targetAccount.username;
this.password = targetAccount.password;
uni.showToast({
title: '已切换到备用账号',
icon: 'success'
});
} else {
// 登录失败
let errorMsg = '账号登录失败,无法切换';
// 检查是否需要手机验证
if (result.responseData && result.responseData.extInfo &&
result.responseData.extInfo.action === "redirect" &&
result.responseData.extInfo.uri && result.responseData.extInfo.uri.includes("请使用手机号验证登录")) {
errorMsg = '该账号需要手机验证,无法切换';
}
uni.showModal({
title: '切换失败',
content: errorMsg,
showCancel: false
});
}
} catch (error) {
console.error('切换账号失败:', error);
uni.showModal({
title: '切换失败',
content: '网络异常或服务器错误,请稍后重试',
showCancel: false
});
} finally {
uni.hideLoading();
}
},
// 删除账号
removeAccount(index) {
uni.showModal({
title: '提示',
content: '确定要删除此账号吗?',
success: (res) => {
if (res.confirm) {
// 检查是否删除的是当前活跃账号
const isActiveAccount = this.accounts[index].isActive;
// 删除账号
this.accounts.splice(index, 1);
// 保存更新后的账号列表
uni.setStorageSync('accounts', JSON.stringify(this.accounts));
// 处理删除后的情况
if (this.accounts.length === 0) {
// 如果没有账号了,清除登录状态
this.isLoggedIn = false;
this.username = '';
this.password = '';
uni.removeStorageSync('KongfzUserName');
uni.removeStorageSync('KongfzPassword');
uni.removeStorageSync('UserInfoCookies');
uni.removeStorageSync('cookies');
this.userInfo = null;
uni.showToast({
title: '所有账号已删除,请重新登录',
icon: 'none'
});
} else if (isActiveAccount) {
// 如果删除的是当前使用账号,则切换到第一个账号
this.setAsActive(0);
}
uni.showToast({
title: '账号删除成功',
icon: 'success'
});
}
}
});
},
// 处理账号切换事件
handleAccountSwitched(event) {
// 在这里处理账号切换事件的逻辑
console.log('账号切换事件:', event);
// 重新加载账号列表
try {
const savedAccounts = uni.getStorageSync('accounts');
if (savedAccounts) {
this.accounts = JSON.parse(savedAccounts);
// 获取当前使用的账号索引
const currentIndex = uni.getStorageSync('currentAccountIndex');
this.currentAccountIndex = currentIndex !== '' ? parseInt(currentIndex) : 0;
// 更新当前用户名和密码
if (this.accounts.length > 0 && this.accounts[this.currentAccountIndex]) {
this.username = this.accounts[this.currentAccountIndex].username;
this.password = this.accounts[this.currentAccountIndex].password;
}
// 如果当前已登录,尝试获取用户信息
if (this.isLoggedIn) {
const cookies = uni.getStorageSync('UserInfoCookies');
if (cookies) {
this.getUserInfo(cookies);
}
}
console.log('账号切换后更新界面完成');
}
} catch (error) {
console.error('处理账号切换事件失败:', error);
}
}
}
}
</script>
<style scoped>
/* 统一设置u-demo-block的顶部外边距为40rpx形成模块间的间距 */
.u-demo-block {
margin-top: 10rpx;
background-color: #ffffff;
padding: 10rpx;
border-radius: 10rpx;
}
::v-deep .login-form-row.data-v-666e420a {
display: flex;
align-items: center;
padding: 1rpx;
gap: 20rpx;
}
.user-info {
display: flex;
align-items: center;
padding: 20rpx;
background-color: #f8f8f8;
border-radius: 12rpx;
margin-bottom: 20rpx;
}
.user-avatar {
width: 100rpx;
height: 100rpx;
border-radius: 50rpx;
overflow: hidden;
margin-right: 20rpx;
border: 2rpx solid #eee;
}
.user-avatar image {
width: 100%;
height: 100%;
}
.user-details {
flex: 1;
display: flex;
flex-direction: column;
gap: 10rpx;
}
.username {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.user-area {
font-size: 24rpx;
color: #666;
}
.logout {
font-size: 24rpx;
color: #666;
padding: 8rpx 16rpx;
background-color: #f5f5f5;
border-radius: 6rpx;
cursor: pointer;
align-self: center;
margin-left: auto;
border: 1rpx solid #e0e0e0;
transition: all 0.3s ease;
}
.logout:active {
background-color: #e0e0e0;
}
.remember-password {
padding: 0 20rpx;
margin-top: -10rpx;
margin-bottom: 15rpx;
}
.checkbox-label {
display: flex;
align-items: center;
font-size: 24rpx;
color: #666;
}
.checkbox-label text {
margin-left: 6rpx;
}
.login-button {
margin-top: 30rpx;
width: 100%;
background-color: #ffffff;
color: #000000;
border: 1px solid #000000;
}
/* 模块标题区域样式 */
.section-header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-bottom: 15rpx;
}
/* 模块主标题样式 */
.section-title {
font-size: 32rpx;
color: #333333;
font-weight: bold;
}
/* 模块副标题样式 */
.section-subtitle {
font-size: 24rpx;
color: #888888;
text-align: right;
white-space: nowrap;
}
/* 价格参考文本区域样式 */
.price-reference {
padding: 15rpx 0;
line-height: 1.5;
}
/* 高亮文本样式 */
.highlight-text {
color: #000000;
font-weight: bold;
}
/* 均价范围控制区域样式 */
.average-range-control {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 15rpx;
}
/* 范围标签样式 */
.range-label {
font-size: 26rpx;
color: #666666;
}
/* 范围控制区域样式 */
.range-control {
display: flex;
align-items: center;
}
/* 范围控制按钮样式 */
.range-btn {
width: 60rpx;
height: 60rpx;
line-height: 60rpx;
text-align: center;
background-color: #f5f5f5;
border-radius: 8rpx;
font-size: 32rpx;
color: #333333;
position: relative;
}
/* 第一个按钮显示减号 */
.range-control .range-btn:first-child::before {
content: "-";
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
font-weight: bold;
}
/* 最后一个按钮显示加号 */
.range-control .range-btn:last-child::before {
content: "+";
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
font-weight: bold;
}
/* 范围值显示样式 */
.range-value {
width: 80rpx;
text-align: center;
font-size: 28rpx;
color: #333333;
}
/* 数字控制器容器样式 */
.number-control-wrapper {
display: flex;
align-items: center;
gap: 10rpx;
padding: 10rpx;
}
/* 控制按钮基础样式 */
.number-control-btn {
width: 60rpx;
height: 60rpx;
background-color: #f5f5f5;
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 32rpx;
color: #333;
cursor: pointer;
}
/* 按钮悬停效果 */
.number-control-btn:active {
background-color: #e0e0e0;
}
/* 减号按钮样式 */
.minus-btn {
font-weight: bold;
}
/* 加号按钮样式 */
.plus-btn {
font-weight: bold;
}
/* 自定义数字输入框样式 */
.custom-input-box {
margin: 0 20rpx;
width: 200rpx;
height: 60rpx;
text-align: center;
background-color: #f8f8f8;
border: 1px solid #dcdfe6;
border-radius: 8rpx;
font-size: 28rpx;
color: #333;
}
/* 运费模板选择器的样式,包括边框、圆角、内边距、背景色、定位和顶部外边距 */
.freight-picker {
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
padding: 20rpx;
background-color: #fff;
position: relative;
margin-top: 20rpx;
}
/* 选择器内容区域的样式,弹性布局实现内容左右分布,设置字体大小和颜色 */
.picker-content {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 28rpx;
color: #606266;
}
/* 选择器箭头的样式,通过边框设置三角形外观 */
.picker-content .arrow {
display: inline-block;
width: 0;
height: 0;
border-left: 8rpx solid transparent;
border-right: 8rpx solid transparent;
border-top: 12rpx solid #909399;
margin-left: 10rpx;
}
/* 自动提交模块容器的样式,包括背景色、内边距、圆角和顶部外边距 */
.auto-submit-container {
background-color: #f5f5f5;
padding: 20rpx;
border-radius: 10rpx;
margin-top: 40rpx;
}
/* 自动提交模块标题部分的底部外边距样式 */
/* .section-title {
margin-bottom: 20rpx;
} */
/* 自动提交模块标题文本的样式,包括颜色、字体大小和加粗 */
.title-text {
color: #333333;
font-size: 32rpx;
font-weight: bold;
}
/* 开关项的样式,弹性布局实现内容左右分布,设置内边距 */
.switch-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15rpx 0;
}
/* 开关项文本的样式,设置颜色和字体大小 */
.switch-item text {
color: #666666;
font-size: 28rpx;
}
/* 核心布局方案 */
.login-form-row {
display: flex;
align-items: center;
padding: 20rpx;
gap: 20rpx;
}
/* 输入框宽度控制 */
.login-input {
flex: 3;
/* 输入框占3份 */
min-width: 200rpx;
/* 最小宽度保障 */
border-radius: 8rpx;
}
/* 按钮样式覆盖 */
.u-button {
flex-shrink: 0 !important;
/* 禁止收缩 */
padding: 0 20rpx !important;
}
::v-depp .u-border {
border-width: 0.5rpx !important;
border-color: #dadbde !important;
border-style: solid;
}
::v-deep .u-button--square.data-v-2bf0e569 {
border-bottom-left-radius: 10rpx;
border-bottom-right-radius: 10rpx;
border-top-left-radius: 10rpx;
border-top-right-radius: 10rpx;
}
/* 微信小程序需用 ::v-deep */
::v-deep .u-textarea__field.data-v-09988a29 {
flex: 1;
font-size: 29rpx;
color: #606266;
width: 100%;
}
/* 唯一class控制布局 */
.custom-layout {
display: flex !important;
justify-content: space-between !important;
/* align-items: center !important; */
width: 100% !important;
padding: 20rpx 0 !important;
}
/* 分段器按钮字体变大适用于uView2的u-subsection */
::v-deep .u-subsection__item {
font-size: 36rpx !important;
height: 70rpx !important;
line-height: 70rpx !important;
padding: 0 30rpx !important;
}
::v-deep .u-subsection__item--active {
font-size: 38rpx !important;
font-weight: bold !important;
color: #111 !important;
background: #2979ff !important;
border-color: #2979ff !important;
}
.u-demo-block__content {
height: auto !important;
overflow: visible !important;
}
::v-deep .u-subsection {
margin-bottom: 40rpx !important;
margin-top: 10rpx !important;
min-height: 70rpx !important;
width: 100% !important;
}
.price-reference {
margin-bottom: 40rpx !important;
margin-top: 30rpx !important;
line-height: 1.8;
min-height: 60rpx;
word-break: break-all;
}
.u-demo-block__content>view[style*="margin-top:20rpx"] {
margin-top: 40rpx !important;
}
::v-deep .u-subsection--button__bar.data-v-78c1286e {
background-color: #c5c5c5;
border-radius: 3rpx !important;
}
/* 多账号管理样式 */
.accounts-manager {
margin-top: 20rpx;
padding: 0 20rpx;
}
.account-list {
margin-top: 10rpx;
}
.account-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15rpx 0;
border-bottom: 1rpx solid #eee;
}
.account-item:last-child {
border-bottom: none;
}
.account-info {
flex: 1;
display: flex;
justify-content: space-between;
align-items: center;
}
.account-username {
font-size: 28rpx;
color: #333;
font-weight: bold;
}
.account-status {
font-size: 24rpx;
color: #666;
padding: 4rpx 10rpx;
border-radius: 6rpx;
border: 1rpx solid #e0e0e0;
}
.account-status.active {
color: #fff;
background-color: #007AFF;
border-color: #007AFF;
}
.account-actions {
display: flex;
gap: 10rpx;
}
.action-btn {
font-size: 24rpx;
color: #007AFF;
padding: 4rpx 10rpx;
border: 1rpx solid #007AFF;
border-radius: 6rpx;
cursor: pointer;
}
.action-btn.delete {
color: #f00;
border-color: #f00;
}
.action-btn:active {
background-color: #e0e0e0;
}
.add-account {
font-size: 24rpx;
color: #007AFF;
padding: 6rpx 12rpx;
border-radius: 6rpx;
cursor: pointer;
background-color: #f0f8ff;
border: 1rpx solid #007AFF;
display: inline-block;
}
/* 添加账号弹窗样式 */
.add-account-popup {
padding: 40rpx;
background-color: #fff;
border-radius: 20rpx;
width: 600rpx;
}
.popup-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
margin-bottom: 30rpx;
text-align: center;
}
.popup-form {
margin-bottom: 30rpx;
}
.popup-input {
margin-bottom: 30rpx;
border: 1rpx solid #dcdfe6;
border-radius: 8rpx;
padding: 10rpx 20rpx;
font-size: 28rpx;
color: #333;
}
.popup-actions {
display: flex;
justify-content: space-around;
gap: 20rpx;
}
.popup-btn {
flex: 1;
height: 80rpx;
line-height: 80rpx;
font-size: 32rpx;
border-radius: 8rpx;
border: none;
}
.popup-btn.cancel {
background-color: #f5f5f5;
color: #333;
}
.popup-btn.confirm {
background-color: #007AFF;
color: #fff;
}
</style>