Compare commits
No commits in common. "82a35cec24aa78c473be01788613ce5368c9c1b1" and "3f144cdf733b5e3558df8e4677e6b0280d50608a" have entirely different histories.
82a35cec24
...
3f144cdf73
@ -55,44 +55,26 @@ async def search_user_inquiry(ns={}):
|
|||||||
# 分页查询
|
# 分页查询
|
||||||
search_sql = """select * from product_inquiry where %s order by update_time desc limit %d offset %d;""" % (where_clause, page_size, offset)
|
search_sql = """select * from product_inquiry where %s order by update_time desc limit %d offset %d;""" % (where_clause, page_size, offset)
|
||||||
result = await sor.sqlExe(search_sql, {})
|
result = await sor.sqlExe(search_sql, {})
|
||||||
dict_sql = """
|
dict_sql = """select dict_type, dict_key, dict_value from product_inquiry_dict where status = 1 order by dict_type asc, sort_order asc;"""
|
||||||
select dict_type, dict_key, dict_value_zh, dict_value_en
|
|
||||||
from product_inquiry_dict
|
|
||||||
where status = 1
|
|
||||||
order by dict_type asc, sort_order asc;
|
|
||||||
"""
|
|
||||||
dict_result = await sor.sqlExe(dict_sql, {})
|
dict_result = await sor.sqlExe(dict_sql, {})
|
||||||
dict_mapping_zh = {}
|
dict_mapping = {}
|
||||||
dict_mapping_en = {}
|
|
||||||
for dict_item in dict_result:
|
for dict_item in dict_result:
|
||||||
dict_type = dict_item.get('dict_type')
|
dict_type = dict_item.get('dict_type')
|
||||||
dict_key = str(dict_item.get('dict_key'))
|
dict_mapping.setdefault(dict_type, {})[str(dict_item.get('dict_key'))] = dict_item.get('dict_value')
|
||||||
dict_mapping_zh.setdefault(dict_type, {})[dict_key] = dict_item.get('dict_value_zh')
|
|
||||||
dict_mapping_en.setdefault(dict_type, {})[dict_key] = dict_item.get('dict_value_en')
|
|
||||||
|
|
||||||
value_mapping_zh = {
|
value_mapping = {
|
||||||
'custom_type': {'0': '个人', '1': '企业'},
|
'custom_type': {'0': '个人', '1': '企业'},
|
||||||
'enterprise_type': dict_mapping_zh.get('enterprise_type', {}),
|
'enterprise_type': dict_mapping.get('enterprise_type', {}),
|
||||||
'region': dict_mapping_zh.get('region', {}),
|
'region': dict_mapping.get('region', {}),
|
||||||
'feedback': {'0': '待回复', '1': '已回复'}
|
'feedback': {'0': '待回复', '1': '已回复'}
|
||||||
}
|
}
|
||||||
value_mapping_en = {
|
|
||||||
'custom_type': {'0': 'Individual', '1': 'Enterprise'},
|
|
||||||
'enterprise_type': dict_mapping_en.get('enterprise_type', {}),
|
|
||||||
'region': dict_mapping_en.get('region', {}),
|
|
||||||
'feedback': {'0': 'Pending Reply', '1': 'Replied'}
|
|
||||||
}
|
|
||||||
for data_dic in result:
|
for data_dic in result:
|
||||||
for key in value_mapping_zh.keys():
|
for key, mapping in value_mapping.items():
|
||||||
if key in data_dic:
|
if key in data_dic:
|
||||||
value_key = str(data_dic.get(key))
|
data_dic['%s_name' % key] = mapping.get(str(data_dic.get(key)), data_dic.get(key))
|
||||||
data_dic['%s_name_zh' % key] = value_mapping_zh[key].get(value_key, data_dic.get(key))
|
direction_mapping = dict_mapping.get('direction', {})
|
||||||
data_dic['%s_name_en' % key] = value_mapping_en[key].get(value_key, data_dic.get(key))
|
|
||||||
direction_mapping_zh = dict_mapping_zh.get('direction', {})
|
|
||||||
direction_mapping_en = dict_mapping_en.get('direction', {})
|
|
||||||
direction_keys = str(data_dic.get('consult_direction')).split(',') if data_dic.get('consult_direction') else []
|
direction_keys = str(data_dic.get('consult_direction')).split(',') if data_dic.get('consult_direction') else []
|
||||||
data_dic['consult_direction_name_zh'] = ','.join([direction_mapping_zh.get(direction_key.strip(), direction_key.strip()) for direction_key in direction_keys if direction_key.strip()])
|
data_dic['consult_direction_name'] = ','.join([direction_mapping.get(direction_key.strip(), direction_key.strip()) for direction_key in direction_keys if direction_key.strip()])
|
||||||
data_dic['consult_direction_name_en'] = ', '.join([direction_mapping_en.get(direction_key.strip(), direction_key.strip()) for direction_key in direction_keys if direction_key.strip()])
|
|
||||||
|
|
||||||
if ns.get('to_excel') == '1':
|
if ns.get('to_excel') == '1':
|
||||||
# 创建映射字段 导出execl
|
# 创建映射字段 导出execl
|
||||||
@ -124,11 +106,11 @@ async def search_user_inquiry(ns={}):
|
|||||||
value = data_dic[key]
|
value = data_dic[key]
|
||||||
chinese_key = field_mapping[key]
|
chinese_key = field_mapping[key]
|
||||||
if key == 'consult_direction':
|
if key == 'consult_direction':
|
||||||
direction_mapping = dict_mapping_zh.get('direction', {})
|
direction_mapping = dict_mapping.get('direction', {})
|
||||||
direction_keys = str(value).split(',') if value else []
|
direction_keys = str(value).split(',') if value else []
|
||||||
new_data_dic[chinese_key] = ','.join([direction_mapping.get(direction_key.strip(), direction_key.strip()) for direction_key in direction_keys if direction_key.strip()])
|
new_data_dic[chinese_key] = ','.join([direction_mapping.get(direction_key.strip(), direction_key.strip()) for direction_key in direction_keys if direction_key.strip()])
|
||||||
elif key in value_mapping_zh:
|
elif key in value_mapping:
|
||||||
mapped_value = value_mapping_zh[key].get(str(value), value) # 若未找到对应映射,保留原始值
|
mapped_value = value_mapping[key].get(str(value), value) # 若未找到对应映射,保留原始值
|
||||||
new_data_dic[chinese_key] = mapped_value
|
new_data_dic[chinese_key] = mapped_value
|
||||||
else:
|
else:
|
||||||
new_data_dic[chinese_key] = value
|
new_data_dic[chinese_key] = value
|
||||||
|
|||||||
@ -4,12 +4,7 @@ async def search_user_inquiry_dict(ns={}):
|
|||||||
where_sql = "where status = 1"
|
where_sql = "where status = 1"
|
||||||
if ns.get('dict_type'):
|
if ns.get('dict_type'):
|
||||||
where_sql += " and dict_type = '%s'" % ns.get('dict_type')
|
where_sql += " and dict_type = '%s'" % ns.get('dict_type')
|
||||||
search_sql = """
|
search_sql = """select * from product_inquiry_dict %s order by dict_type asc, sort_order asc;""" % where_sql
|
||||||
select id, dict_type, dict_key, dict_value_zh, dict_value_en, sort_order
|
|
||||||
from product_inquiry_dict
|
|
||||||
%s
|
|
||||||
order by dict_type asc, sort_order asc;
|
|
||||||
""" % where_sql
|
|
||||||
result = await sor.sqlExe(search_sql, {})
|
result = await sor.sqlExe(search_sql, {})
|
||||||
return {
|
return {
|
||||||
'status': True,
|
'status': True,
|
||||||
|
|||||||
@ -1,39 +0,0 @@
|
|||||||
# Bilingual Inquiry Dictionary Implementation Plan
|
|
||||||
|
|
||||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
||||||
|
|
||||||
**Goal:** Adapt inquiry search APIs to the bilingual dictionary value columns.
|
|
||||||
|
|
||||||
**Architecture:** Build independent Chinese and English dictionary maps from one query. Return separate language display fields in normal search results while reusing the Chinese map for the existing Excel export.
|
|
||||||
|
|
||||||
**Tech Stack:** DSPY Python endpoints, async DBPools/sor access, MySQL.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Task 1: Update inquiry result mapping
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `b/product/search_user_inquiry.dspy`
|
|
||||||
|
|
||||||
- [ ] Query `dict_value_zh` and `dict_value_en`.
|
|
||||||
- [ ] Build separate Chinese and English maps.
|
|
||||||
- [ ] Return `*_name_zh` and `*_name_en` for single-choice fields.
|
|
||||||
- [ ] Return `consult_direction_name_zh` and `consult_direction_name_en`.
|
|
||||||
- [ ] Keep Excel export mapped through Chinese values.
|
|
||||||
|
|
||||||
### Task 2: Update dictionary search output
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Modify: `b/product/search_user_inquiry_dict.dspy`
|
|
||||||
|
|
||||||
- [ ] Replace `select *` with the explicit bilingual dictionary columns.
|
|
||||||
|
|
||||||
### Task 3: Verify
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- Verify: `b/product/search_user_inquiry.dspy`
|
|
||||||
- Verify: `b/product/search_user_inquiry_dict.dspy`
|
|
||||||
|
|
||||||
- [ ] Confirm neither SQL query references the removed `dict_value` column.
|
|
||||||
- [ ] Compile both DSPY function bodies.
|
|
||||||
- [ ] Run IDE diagnostics and `git diff --check`.
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
# 咨询字典双语接口设计
|
|
||||||
|
|
||||||
## 目标
|
|
||||||
|
|
||||||
咨询相关接口适配 `product_inquiry_dict` 的双语字段
|
|
||||||
`dict_value_zh` 和 `dict_value_en`,不再读取旧字段 `dict_value`。
|
|
||||||
|
|
||||||
## 接口调整
|
|
||||||
|
|
||||||
- `search_user_inquiry.dspy` 同时查询并构建中英文映射。
|
|
||||||
- 普通咨询列表分别返回 `*_name_zh` 和 `*_name_en`。
|
|
||||||
- 单选字段包括客户类型、企业类型、区域和反馈状态。
|
|
||||||
- 多选咨询方向分别返回 `consult_direction_name_zh` 和
|
|
||||||
`consult_direction_name_en`,并保持原选项顺序。
|
|
||||||
- Excel 导出继续使用中文表头和中文字典值。
|
|
||||||
- `search_user_inquiry_dict.dspy` 明确返回
|
|
||||||
`id`、`dict_type`、`dict_key`、`dict_value_zh`、
|
|
||||||
`dict_value_en`、`sort_order`。
|
|
||||||
|
|
||||||
## 兼容边界
|
|
||||||
|
|
||||||
旧的 `*_name` 单语字段不再生成。调用方应读取对应的
|
|
||||||
`*_name_zh` 或 `*_name_en` 字段。
|
|
||||||
|
|
||||||
## 验证
|
|
||||||
|
|
||||||
- 字典查询不再引用 `dict_value`。
|
|
||||||
- 普通列表中的单选和多选字段均包含中英文显示名称。
|
|
||||||
- Excel 仍只输出中文显示值。
|
|
||||||
@ -2,9 +2,7 @@
|
|||||||
position: relative;
|
position: relative;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: hidden;
|
|
||||||
color: #1f2937;
|
color: #1f2937;
|
||||||
padding: 0 12%;
|
|
||||||
background:
|
background:
|
||||||
radial-gradient(circle at 78% 18%, rgba(236, 72, 153, 0.07) 0%, rgba(236, 72, 153, 0) 32%),
|
radial-gradient(circle at 78% 18%, rgba(236, 72, 153, 0.07) 0%, rgba(236, 72, 153, 0) 32%),
|
||||||
radial-gradient(circle at 18% 16%, rgba(59, 130, 246, 0.12) 0%, rgba(59, 130, 246, 0) 36%),
|
radial-gradient(circle at 18% 16%, rgba(59, 130, 246, 0.12) 0%, rgba(59, 130, 246, 0) 36%),
|
||||||
@ -12,10 +10,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.news-shell {
|
.news-shell {
|
||||||
// position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
// max-width: 1280px;
|
max-width: 1280px;
|
||||||
// margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 0 24px;
|
padding: 0 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,9 +55,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.news-hero {
|
.news-hero {
|
||||||
// position: relative;
|
position: relative;
|
||||||
padding: 140px 0 72px;
|
padding: 140px 0 72px;
|
||||||
// overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.news-hero::before {
|
.news-hero::before {
|
||||||
@ -95,8 +93,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.hero-content {
|
.hero-content {
|
||||||
text-align: left;
|
|
||||||
margin: 0 ;
|
|
||||||
animation: fadeInUp 0.8s ease-out forwards;
|
animation: fadeInUp 0.8s ease-out forwards;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,7 +197,6 @@
|
|||||||
.news-item {
|
.news-item {
|
||||||
position: relative;
|
position: relative;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border: 1px solid rgba(0, 0, 0, 0.04);
|
border: 1px solid rgba(0, 0, 0, 0.04);
|
||||||
|
|||||||
@ -401,59 +401,5 @@ export default {
|
|||||||
openedDecision: 'The Investment Strategy Agent page has been opened.<br>Anything else you would like to know?',
|
openedDecision: 'The Investment Strategy Agent page has been opened.<br>Anything else you would like to know?',
|
||||||
openedPage: 'The related page has been opened. Anything else you would like to know?'
|
openedPage: 'The related page has been opened. Anything else you would like to know?'
|
||||||
},
|
},
|
||||||
loginDialog: {
|
|
||||||
welcomeLogin: 'Welcome',
|
|
||||||
createAccount: 'Create Account',
|
|
||||||
signIn: 'Sign In',
|
|
||||||
signUp: 'Sign Up',
|
|
||||||
signInWithPassword: 'Password',
|
|
||||||
signInWithCode: 'Verification Code',
|
|
||||||
enterAccount: 'Enter account',
|
|
||||||
enterPassword: 'Enter password',
|
|
||||||
enterMobile: 'Enter mobile number',
|
|
||||||
enterVerificationCode: 'Enter verification code',
|
|
||||||
enterAccountName: 'Enter account name',
|
|
||||||
forgotPassword: 'Forgot password?',
|
|
||||||
noAccountSignUp: 'No account? Sign Up',
|
|
||||||
signInNow: 'Sign In',
|
|
||||||
getVerificationCode: 'Get Verification Code',
|
|
||||||
agreePrefix: 'I have read and agree to the ',
|
|
||||||
userAgreement: 'User Agreement',
|
|
||||||
agreeAnd: ' and ',
|
|
||||||
privacyPolicy: 'Privacy Policy',
|
|
||||||
signUpNow: 'Sign Up',
|
|
||||||
hasAccountSignIn: 'Already have an account? Sign In',
|
|
||||||
signingIn: 'Signing in...',
|
|
||||||
signingUp: 'Signing up...',
|
|
||||||
resendCode: 'Resend {seconds}s',
|
|
||||||
mobileRequired: 'Enter mobile number',
|
|
||||||
mobileInvalid: 'Please enter a valid mobile number',
|
|
||||||
accountRequired: 'Enter account',
|
|
||||||
passwordRequired: 'Enter password',
|
|
||||||
codeRequired: 'Enter verification code',
|
|
||||||
accountNameRequired: 'Enter account name',
|
|
||||||
agreeRequired: 'Please read and agree to the agreements first',
|
|
||||||
codeSent: 'Verification code sent',
|
|
||||||
codeSendFail: 'Failed to get verification code',
|
|
||||||
loginFail: 'Sign in failed',
|
|
||||||
loginSuccess: 'Signed in successfully',
|
|
||||||
registerSuccess: 'Registration successful. Please sign in.',
|
|
||||||
registerFail: 'Registration failed',
|
|
||||||
registerRetry: 'Registration failed. Please try again.',
|
|
||||||
resetPassword: 'Reset Password',
|
|
||||||
resetPasswordDesc: 'Verify identity via mobile verification code to set a new password',
|
|
||||||
mobileLabel: 'Mobile Number',
|
|
||||||
newPasswordLabel: 'New Password',
|
|
||||||
verificationCodeLabel: 'Verification Code',
|
|
||||||
enterBoundMobile: 'Enter bound mobile number',
|
|
||||||
enterNewPassword: 'Enter new password',
|
|
||||||
cancel: 'Cancel',
|
|
||||||
confirmReset: 'Confirm Reset',
|
|
||||||
newPasswordRequired: 'Enter new password',
|
|
||||||
getCodeFirst: 'Please get the verification code first',
|
|
||||||
resetSuccess: 'Password reset successfully',
|
|
||||||
resetFail: 'Password reset failed',
|
|
||||||
codeSentCheck: 'Verification code sent. Please check your messages.'
|
|
||||||
},
|
|
||||||
...autoMessages
|
...autoMessages
|
||||||
}
|
}
|
||||||
|
|||||||
@ -401,59 +401,5 @@ export default {
|
|||||||
openedDecision: '已为您打开投策智能体页面 📊<br>还有其他想了解的吗?',
|
openedDecision: '已为您打开投策智能体页面 📊<br>还有其他想了解的吗?',
|
||||||
openedPage: '已为您打开相关页面。还有其他想了解的吗?'
|
openedPage: '已为您打开相关页面。还有其他想了解的吗?'
|
||||||
},
|
},
|
||||||
loginDialog: {
|
|
||||||
welcomeLogin: '欢迎登录',
|
|
||||||
createAccount: '创建账号',
|
|
||||||
signIn: '登录',
|
|
||||||
signUp: '注册',
|
|
||||||
signInWithPassword: '密码登录',
|
|
||||||
signInWithCode: '验证码登录',
|
|
||||||
enterAccount: '请输入账户',
|
|
||||||
enterPassword: '请输入密码',
|
|
||||||
enterMobile: '请输入手机号',
|
|
||||||
enterVerificationCode: '请输入验证码',
|
|
||||||
enterAccountName: '请输入账户名',
|
|
||||||
forgotPassword: '忘记密码?',
|
|
||||||
noAccountSignUp: '没有账号?去注册',
|
|
||||||
signInNow: '立即登录',
|
|
||||||
getVerificationCode: '获取验证码',
|
|
||||||
agreePrefix: '我已阅读并同意',
|
|
||||||
userAgreement: '《用户协议》',
|
|
||||||
agreeAnd: '、',
|
|
||||||
privacyPolicy: '《隐私政策》',
|
|
||||||
signUpNow: '立即注册',
|
|
||||||
hasAccountSignIn: '已有账号?前往登录',
|
|
||||||
signingIn: '登录中...',
|
|
||||||
signingUp: '注册中...',
|
|
||||||
resendCode: '重新发送 {seconds}s',
|
|
||||||
mobileRequired: '请输入手机号',
|
|
||||||
mobileInvalid: '请输入正确的手机号',
|
|
||||||
accountRequired: '请输入账户',
|
|
||||||
passwordRequired: '请输入密码',
|
|
||||||
codeRequired: '请输入验证码',
|
|
||||||
accountNameRequired: '请输入账户名',
|
|
||||||
agreeRequired: '请先阅读并同意相关协议',
|
|
||||||
codeSent: '验证码已发送',
|
|
||||||
codeSendFail: '验证码获取失败',
|
|
||||||
loginFail: '登录失败',
|
|
||||||
loginSuccess: '登录成功',
|
|
||||||
registerSuccess: '注册成功,请登录',
|
|
||||||
registerFail: '注册失败',
|
|
||||||
registerRetry: '注册失败,请重试',
|
|
||||||
resetPassword: '重置密码',
|
|
||||||
resetPasswordDesc: '通过手机号验证码验证身份后设置新密码',
|
|
||||||
mobileLabel: '手机号',
|
|
||||||
newPasswordLabel: '新密码',
|
|
||||||
verificationCodeLabel: '验证码',
|
|
||||||
enterBoundMobile: '请输入绑定手机号',
|
|
||||||
enterNewPassword: '请输入新密码',
|
|
||||||
cancel: '取消',
|
|
||||||
confirmReset: '确认重置',
|
|
||||||
newPasswordRequired: '请输入新密码',
|
|
||||||
getCodeFirst: '请先获取验证码',
|
|
||||||
resetSuccess: '密码重置成功',
|
|
||||||
resetFail: '密码重置失败',
|
|
||||||
codeSentCheck: '验证码已发送,请注意查收。'
|
|
||||||
},
|
|
||||||
...autoMessages
|
...autoMessages
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,31 +13,31 @@
|
|||||||
<div class="brand-area">
|
<div class="brand-area">
|
||||||
|
|
||||||
<div class="brand-text">
|
<div class="brand-text">
|
||||||
<h2>{{ activeTab === 'login' ? $t('loginDialog.welcomeLogin') : $t('loginDialog.createAccount') }}</h2>
|
<h2>{{ activeTab === 'login' ? '欢迎登录' : '创建账号' }}</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="tab-group">
|
<div class="tab-group">
|
||||||
<button type="button" :class="{ active: activeTab === 'login' }" @click="switchTab('login')">{{ $t('loginDialog.signIn') }}</button>
|
<button type="button" :class="{ active: activeTab === 'login' }" @click="switchTab('login')">登录</button>
|
||||||
<button type="button" :class="{ active: activeTab === 'register' }" @click="switchTab('register')">{{ $t('loginDialog.signUp') }}</button>
|
<button type="button" :class="{ active: activeTab === 'register' }" @click="switchTab('register')">注册</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="activeTab === 'login'" class="form-panel">
|
<div v-if="activeTab === 'login'" class="form-panel">
|
||||||
<div class="mode-tabs">
|
<div class="mode-tabs">
|
||||||
<button type="button" :class="{ active: loginMode === 'password' }" @click="switchLoginMode('password')">{{ $t('loginDialog.signInWithPassword') }}</button>
|
<button type="button" :class="{ active: loginMode === 'password' }" @click="switchLoginMode('password')">密码登录</button>
|
||||||
<button type="button" :class="{ active: loginMode === 'mobile' }" @click="switchLoginMode('mobile')">{{ $t('loginDialog.signInWithCode') }}</button>
|
<button type="button" :class="{ active: loginMode === 'mobile' }" @click="switchLoginMode('mobile')">验证码登录</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form ref="loginForm" :model="loginForm" :rules="activeLoginRules" label-position="top">
|
<el-form ref="loginForm" :model="loginForm" :rules="activeLoginRules" label-position="top">
|
||||||
<template v-if="loginMode === 'password'">
|
<template v-if="loginMode === 'password'">
|
||||||
<el-form-item prop="username">
|
<el-form-item prop="username">
|
||||||
<el-input v-model.trim="loginForm.username" :placeholder="$t('loginDialog.enterAccount')" prefix-icon="el-icon-user" @keyup.enter.native="handleLogin" />
|
<el-input v-model.trim="loginForm.username" placeholder="请输入账户" prefix-icon="el-icon-user" @keyup.enter.native="handleLogin" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="password">
|
<el-form-item prop="password">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="loginForm.password"
|
v-model="loginForm.password"
|
||||||
:type="loginPwdVisible ? 'text' : 'password'"
|
:type="loginPwdVisible ? 'text' : 'password'"
|
||||||
:placeholder="$t('loginDialog.enterPassword')"
|
placeholder="请输入密码"
|
||||||
prefix-icon="el-icon-lock"
|
prefix-icon="el-icon-lock"
|
||||||
@keyup.enter.native="handleLogin"
|
@keyup.enter.native="handleLogin"
|
||||||
>
|
>
|
||||||
@ -48,11 +48,11 @@
|
|||||||
|
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<el-form-item prop="mobile">
|
<el-form-item prop="mobile">
|
||||||
<el-input v-model.trim="loginForm.mobile" :placeholder="$t('loginDialog.enterMobile')" prefix-icon="el-icon-mobile-phone" />
|
<el-input v-model.trim="loginForm.mobile" placeholder="请输入手机号" prefix-icon="el-icon-mobile-phone" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="vcode">
|
<el-form-item prop="vcode">
|
||||||
<div class="code-row">
|
<div class="code-row">
|
||||||
<el-input v-model.trim="loginForm.vcode" :placeholder="$t('loginDialog.enterVerificationCode')" prefix-icon="el-icon-key" @keyup.enter.native="handleLogin" />
|
<el-input v-model.trim="loginForm.vcode" placeholder="请输入验证码" prefix-icon="el-icon-key" @keyup.enter.native="handleLogin" />
|
||||||
<button type="button" class="code-btn" :disabled="loginCodeDisabled" @click="getLoginCode">{{ loginCodeText }}</button>
|
<button type="button" class="code-btn" :disabled="loginCodeDisabled" @click="getLoginCode">{{ loginCodeText }}</button>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@ -60,36 +60,36 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<div class="form-actions">
|
<div class="form-actions">
|
||||||
<button type="button" class="text-btn" @click="forgotPasswordVisible = true">{{ $t('loginDialog.forgotPassword') }}</button>
|
<button type="button" class="text-btn" @click="forgotPasswordVisible = true">忘记密码?</button>
|
||||||
<button type="button" class="text-btn" @click="switchTab('register')">{{ $t('loginDialog.noAccountSignUp') }}</button>
|
<button type="button" class="text-btn" @click="switchTab('register')">没有账号?去注册</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button" class="main-btn" :disabled="loginLoading" @click="handleLogin">
|
<button type="button" class="main-btn" :disabled="loginLoading" @click="handleLogin">
|
||||||
{{ loginLoading ? $t('loginDialog.signingIn') : $t('loginDialog.signInNow') }}
|
{{ loginLoading ? '登录中...' : '立即登录' }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="form-panel">
|
<div v-else class="form-panel">
|
||||||
<el-form ref="registerForm" :model="registerForm" :rules="registerRules" label-position="top">
|
<el-form ref="registerForm" :model="registerForm" :rules="registerRules" label-position="top">
|
||||||
<el-form-item prop="mobile">
|
<el-form-item prop="mobile">
|
||||||
<el-input v-model.trim="registerForm.mobile" class="phone-input" :placeholder="$t('loginDialog.enterMobile')">
|
<el-input v-model.trim="registerForm.mobile" class="phone-input" placeholder="请输入手机号">
|
||||||
<span slot="prefix" class="country-prefix">+86</span>
|
<span slot="prefix" class="country-prefix">+86</span>
|
||||||
</el-input>
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="vcode">
|
<el-form-item prop="vcode">
|
||||||
<div class="code-row">
|
<div class="code-row">
|
||||||
<el-input v-model.trim="registerForm.vcode" :placeholder="$t('loginDialog.enterVerificationCode')" prefix-icon="el-icon-key" />
|
<el-input v-model.trim="registerForm.vcode" placeholder="请输入验证码" prefix-icon="el-icon-key" />
|
||||||
<button type="button" class="code-btn" :disabled="regCodeDisabled" @click="getRegisterCode">{{ regCodeText }}</button>
|
<button type="button" class="code-btn" :disabled="regCodeDisabled" @click="getRegisterCode">{{ regCodeText }}</button>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="username">
|
<el-form-item prop="username">
|
||||||
<el-input v-model.trim="registerForm.username" :placeholder="$t('loginDialog.enterAccountName')" prefix-icon="el-icon-user" />
|
<el-input v-model.trim="registerForm.username" placeholder="请输入账户名" prefix-icon="el-icon-user" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="password">
|
<el-form-item prop="password">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="registerForm.password"
|
v-model="registerForm.password"
|
||||||
:type="regPwdVisible ? 'text' : 'password'"
|
:type="regPwdVisible ? 'text' : 'password'"
|
||||||
:placeholder="$t('loginDialog.enterPassword')"
|
placeholder="请输入密码"
|
||||||
prefix-icon="el-icon-lock"
|
prefix-icon="el-icon-lock"
|
||||||
@keyup.enter.native="handleRegister"
|
@keyup.enter.native="handleRegister"
|
||||||
>
|
>
|
||||||
@ -100,18 +100,19 @@
|
|||||||
|
|
||||||
<div class="agreement-wrap">
|
<div class="agreement-wrap">
|
||||||
<el-checkbox v-model="registerForm.agree">
|
<el-checkbox v-model="registerForm.agree">
|
||||||
{{ $t('loginDialog.agreePrefix') }}
|
我已阅读并同意
|
||||||
<a class="agreement-link" :href="getAgreementUrl('user')" target="_blank" rel="noopener noreferrer" @click.stop>{{ $t('loginDialog.userAgreement') }}</a>
|
<a class="agreement-link" :href="getAgreementUrl('user')" target="_blank" rel="noopener noreferrer" @click.stop>《用户协议》</a>
|
||||||
{{ $t('loginDialog.agreeAnd') }}
|
、
|
||||||
<a class="agreement-link" :href="getAgreementUrl('privacy')" target="_blank" rel="noopener noreferrer" @click.stop>{{ $t('loginDialog.privacyPolicy') }}</a>
|
<a class="agreement-link" :href="getAgreementUrl('privacy')" target="_blank" rel="noopener noreferrer" @click.stop>《隐私政策》</a>
|
||||||
|
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button type="button" class="main-btn" :disabled="registerLoading" @click="handleRegister">
|
<button type="button" class="main-btn" :disabled="registerLoading" @click="handleRegister">
|
||||||
{{ registerLoading ? $t('loginDialog.signingUp') : $t('loginDialog.signUpNow') }}
|
{{ registerLoading ? '注册中...' : '立即注册' }}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button type="button" class="bottom-link" @click="switchTab('login')">{{ $t('loginDialog.hasAccountSignIn') }}</button>
|
<button type="button" class="bottom-link" @click="switchTab('login')">已有账号?前往登录</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
@ -138,6 +139,12 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
const validatePhone = (rule, value, callback) => {
|
||||||
|
if (!value) callback(new Error('请输入手机号'))
|
||||||
|
else if (!/^1[3-9]\d{9}$/.test(value)) callback(new Error('请输入正确的手机号'))
|
||||||
|
else callback()
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
activeTab: 'login',
|
activeTab: 'login',
|
||||||
loginMode: 'password',
|
loginMode: 'password',
|
||||||
@ -148,8 +155,8 @@ export default {
|
|||||||
regPwdVisible: false,
|
regPwdVisible: false,
|
||||||
loginCodeDisabled: false,
|
loginCodeDisabled: false,
|
||||||
regCodeDisabled: false,
|
regCodeDisabled: false,
|
||||||
loginCodeText: '',
|
loginCodeText: '获取验证码',
|
||||||
regCodeText: '',
|
regCodeText: '获取验证码',
|
||||||
loginTimer: null,
|
loginTimer: null,
|
||||||
regTimer: null,
|
regTimer: null,
|
||||||
loginCount: 60,
|
loginCount: 60,
|
||||||
@ -171,6 +178,18 @@ export default {
|
|||||||
agree: false,
|
agree: false,
|
||||||
wechat_openid: localStorage.getItem('wechat_openid') || '',
|
wechat_openid: localStorage.getItem('wechat_openid') || '',
|
||||||
domain_name: window.location.hostname
|
domain_name: window.location.hostname
|
||||||
|
},
|
||||||
|
loginRules: {
|
||||||
|
username: [{ required: true, message: '请输入账户', trigger: 'blur' }],
|
||||||
|
password: [{ required: true, message: '请输入密码', trigger: 'blur' }],
|
||||||
|
mobile: [{ required: true, validator: validatePhone, trigger: 'blur' }],
|
||||||
|
vcode: [{ required: true, message: '请输入验证码', trigger: 'blur' }]
|
||||||
|
},
|
||||||
|
registerRules: {
|
||||||
|
mobile: [{ required: true, validator: validatePhone, trigger: 'blur' }],
|
||||||
|
vcode: [{ required: true, message: '请输入验证码', trigger: 'blur' }],
|
||||||
|
username: [{ required: true, message: '请输入账户名', trigger: 'blur' }],
|
||||||
|
password: [{ required: true, message: '请输入密码', trigger: 'blur' }]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -194,50 +213,13 @@ export default {
|
|||||||
username: this.loginRules.username,
|
username: this.loginRules.username,
|
||||||
password: this.loginRules.password
|
password: this.loginRules.password
|
||||||
}
|
}
|
||||||
},
|
|
||||||
loginRules() {
|
|
||||||
return {
|
|
||||||
username: [{ required: true, message: this.$t('loginDialog.accountRequired'), trigger: 'blur' }],
|
|
||||||
password: [{ required: true, message: this.$t('loginDialog.passwordRequired'), trigger: 'blur' }],
|
|
||||||
mobile: [{ required: true, validator: this.validatePhone, trigger: 'blur' }],
|
|
||||||
vcode: [{ required: true, message: this.$t('loginDialog.codeRequired'), trigger: 'blur' }]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
registerRules() {
|
|
||||||
return {
|
|
||||||
mobile: [{ required: true, validator: this.validatePhone, trigger: 'blur' }],
|
|
||||||
vcode: [{ required: true, message: this.$t('loginDialog.codeRequired'), trigger: 'blur' }],
|
|
||||||
username: [{ required: true, message: this.$t('loginDialog.accountNameRequired'), trigger: 'blur' }],
|
|
||||||
password: [{ required: true, message: this.$t('loginDialog.passwordRequired'), trigger: 'blur' }]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
'$i18n.locale'() {
|
|
||||||
this.resetCodeButtonText()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.resetCodeButtonText()
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
clearInterval(this.loginTimer)
|
clearInterval(this.loginTimer)
|
||||||
clearInterval(this.regTimer)
|
clearInterval(this.regTimer)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
validatePhone(rule, value, callback) {
|
|
||||||
if (!value) callback(new Error(this.$t('loginDialog.mobileRequired')))
|
|
||||||
else if (!/^1[3-9]\d{9}$/.test(value)) callback(new Error(this.$t('loginDialog.mobileInvalid')))
|
|
||||||
else callback()
|
|
||||||
},
|
|
||||||
resetCodeButtonText() {
|
|
||||||
if (!this.loginCodeDisabled) {
|
|
||||||
this.loginCodeText = this.$t('loginDialog.getVerificationCode')
|
|
||||||
}
|
|
||||||
if (!this.regCodeDisabled) {
|
|
||||||
this.regCodeText = this.$t('loginDialog.getVerificationCode')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleClose() {
|
handleClose() {
|
||||||
this.loginLoading = false
|
this.loginLoading = false
|
||||||
this.registerLoading = false
|
this.registerLoading = false
|
||||||
@ -302,18 +284,18 @@ export default {
|
|||||||
clearInterval(this[timerKey])
|
clearInterval(this[timerKey])
|
||||||
this[countKey] = 59
|
this[countKey] = 59
|
||||||
this[disabledKey] = true
|
this[disabledKey] = true
|
||||||
this[textKey] = this.$t('loginDialog.resendCode', { seconds: this[countKey] })
|
this[textKey] = `重新发送 ${this[countKey]}s`
|
||||||
this[timerKey] = setInterval(() => {
|
this[timerKey] = setInterval(() => {
|
||||||
if (this[countKey] > 0) {
|
if (this[countKey] > 0) {
|
||||||
this[countKey] -= 1
|
this[countKey] -= 1
|
||||||
this[textKey] = this.$t('loginDialog.resendCode', { seconds: this[countKey] })
|
this[textKey] = `重新发送 ${this[countKey]}s`
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
clearInterval(this[timerKey])
|
clearInterval(this[timerKey])
|
||||||
this[timerKey] = null
|
this[timerKey] = null
|
||||||
this[countKey] = 60
|
this[countKey] = 60
|
||||||
this[disabledKey] = false
|
this[disabledKey] = false
|
||||||
this[textKey] = this.$t('loginDialog.getVerificationCode')
|
this[textKey] = '获取验证码'
|
||||||
}, 1000)
|
}, 1000)
|
||||||
},
|
},
|
||||||
getLoginCode() {
|
getLoginCode() {
|
||||||
@ -324,12 +306,12 @@ export default {
|
|||||||
if (res.status) {
|
if (res.status) {
|
||||||
this.loginForm.codeid = res.codeid || (res.data && res.data.codeid) || ''
|
this.loginForm.codeid = res.codeid || (res.data && res.data.codeid) || ''
|
||||||
this.startCountdown('login')
|
this.startCountdown('login')
|
||||||
this.$message.success(this.$t('loginDialog.codeSent'))
|
this.$message.success('验证码已发送')
|
||||||
} else {
|
} else {
|
||||||
this.$message.error(res.msg || this.$t('loginDialog.codeSendFail'))
|
this.$message.error(res.msg || '验证码获取失败')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$message.error(this.$t('loginDialog.codeSendFail'))
|
this.$message.error('验证码获取失败')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -341,12 +323,12 @@ export default {
|
|||||||
if (res.status) {
|
if (res.status) {
|
||||||
this.registerForm.codeid = res.codeid || (res.data && res.data.codeid) || res.data || ''
|
this.registerForm.codeid = res.codeid || (res.data && res.data.codeid) || res.data || ''
|
||||||
this.startCountdown('register')
|
this.startCountdown('register')
|
||||||
this.$message.success(this.$t('loginDialog.codeSent'))
|
this.$message.success('验证码已发送')
|
||||||
} else {
|
} else {
|
||||||
this.$message.error(res.msg || this.$t('loginDialog.codeSendFail'))
|
this.$message.error(res.msg || '验证码获取失败')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$message.error(this.$t('loginDialog.codeSendFail'))
|
this.$message.error('验证码获取失败')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -358,12 +340,12 @@ export default {
|
|||||||
try {
|
try {
|
||||||
const check = await logintypeAPI(loginParams)
|
const check = await logintypeAPI(loginParams)
|
||||||
if (!check.status) {
|
if (!check.status) {
|
||||||
this.$message.error(check.msg || this.$t('loginDialog.loginFail'))
|
this.$message.error(check.msg || '登录失败')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const res = await this.$store.dispatch('user/login', loginParams)
|
const res = await this.$store.dispatch('user/login', loginParams)
|
||||||
if (!res.status) {
|
if (!res.status) {
|
||||||
this.$message.error(res.msg || this.$t('loginDialog.loginFail'))
|
this.$message.error(res.msg || '登录失败')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,12 +377,12 @@ export default {
|
|||||||
})
|
})
|
||||||
router.addRoutes(accessRoutes)
|
router.addRoutes(accessRoutes)
|
||||||
|
|
||||||
this.$message.success(res.msg || this.$t('loginDialog.loginSuccess'))
|
this.$message.success(res.msg || '登录成功')
|
||||||
this.dialogVisible = false
|
this.dialogVisible = false
|
||||||
this.$emit('success', res)
|
this.$emit('success', res)
|
||||||
this.redirectAfterLogin(res)
|
this.redirectAfterLogin(res)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$message.error((error && error.msg) || this.$t('loginDialog.loginFail'))
|
this.$message.error((error && error.msg) || '登录失败')
|
||||||
} finally {
|
} finally {
|
||||||
this.loginLoading = false
|
this.loginLoading = false
|
||||||
}
|
}
|
||||||
@ -452,7 +434,7 @@ export default {
|
|||||||
},
|
},
|
||||||
handleRegister() {
|
handleRegister() {
|
||||||
if (!this.registerForm.agree) {
|
if (!this.registerForm.agree) {
|
||||||
this.$message.warning(this.$t('loginDialog.agreeRequired'))
|
this.$message.warning('请先阅读并同意相关协议')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.$refs.registerForm.validate(async valid => {
|
this.$refs.registerForm.validate(async valid => {
|
||||||
@ -472,17 +454,17 @@ export default {
|
|||||||
}
|
}
|
||||||
const res = await register(registerData)
|
const res = await register(registerData)
|
||||||
if (res.status) {
|
if (res.status) {
|
||||||
this.$message.success(this.$t('loginDialog.registerSuccess'))
|
this.$message.success('注册成功,请登录')
|
||||||
this.loginForm.mobile = this.registerForm.mobile
|
this.loginForm.mobile = this.registerForm.mobile
|
||||||
this.switchTab('login')
|
this.switchTab('login')
|
||||||
this.loginMode = 'mobile'
|
this.loginMode = 'mobile'
|
||||||
this.$refs.registerForm.resetFields()
|
this.$refs.registerForm.resetFields()
|
||||||
this.registerForm.agree = false
|
this.registerForm.agree = false
|
||||||
} else {
|
} else {
|
||||||
this.$message.error(res.message || res.msg || this.$t('loginDialog.registerFail'))
|
this.$message.error(res.message || res.msg || '注册失败')
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$message.error(this.$t('loginDialog.registerRetry'))
|
this.$message.error('注册失败,请重试')
|
||||||
} finally {
|
} finally {
|
||||||
this.registerLoading = false
|
this.registerLoading = false
|
||||||
}
|
}
|
||||||
@ -646,7 +628,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.form-panel ::v-deep .el-form-item {
|
.form-panel ::v-deep .el-form-item {
|
||||||
margin-bottom: 22px;
|
margin-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-panel ::v-deep .el-form-item__error {
|
.form-panel ::v-deep .el-form-item__error {
|
||||||
|
|||||||
@ -54,13 +54,7 @@
|
|||||||
<button v-if="!isNcmatchDomain" type="button" class="nav-item" @click.stop="goHomeAnchor('cases-section')">
|
<button v-if="!isNcmatchDomain" type="button" class="nav-item" @click.stop="goHomeAnchor('cases-section')">
|
||||||
{{ $t('topbar.cases') }}
|
{{ $t('topbar.cases') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button v-if="!isNcmatchDomain" type="button" class="nav-item" @click.stop="goHomeAnchor('news')">
|
||||||
v-if="!isNcmatchDomain"
|
|
||||||
type="button"
|
|
||||||
class="nav-item"
|
|
||||||
:class="{ active: isActiveNews }"
|
|
||||||
@click.stop="navigateTo('/homePage/news')"
|
|
||||||
>
|
|
||||||
{{ $t('topbar.news') }}
|
{{ $t('topbar.news') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@ -335,9 +329,6 @@ export default Vue.extend({
|
|||||||
? this.$route.path.includes('/ncmatchHome/index')
|
? this.$route.path.includes('/ncmatchHome/index')
|
||||||
: this.$route.path.includes('/homePage/index')
|
: this.$route.path.includes('/homePage/index')
|
||||||
},
|
},
|
||||||
isActiveNews() {
|
|
||||||
return this.$route.path.includes('/homePage/news')
|
|
||||||
},
|
|
||||||
langToggleText() {
|
langToggleText() {
|
||||||
return this.activeLocale === 'en-US' ? 'EN/中' : '中/EN'
|
return this.activeLocale === 'en-US' ? 'EN/中' : '中/EN'
|
||||||
},
|
},
|
||||||
@ -471,24 +462,15 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
goHomeAnchor(id) {
|
goHomeAnchor(id) {
|
||||||
this.closeProductPanelImmediate()
|
this.closeProductPanelImmediate()
|
||||||
const scrollToTarget = (attempt = 0) => {
|
const scrollToTarget = () => {
|
||||||
const target = document.getElementById(id)
|
const target = document.getElementById(id)
|
||||||
if (target) {
|
if (target) target.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
||||||
target.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (attempt < 30) {
|
|
||||||
window.setTimeout(() => scrollToTarget(attempt + 1), 100)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
if (this.$route.path.includes('/homePage/index')) {
|
if (this.$route.path.includes('/homePage/index')) {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(scrollToTarget)
|
||||||
window.setTimeout(() => scrollToTarget(), 80)
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.$router.push({ path: '/homePage/index', query: { anchor: id } }).catch(() => {})
|
this.$router.push('/homePage/index').then(() => this.$nextTick(scrollToTarget)).catch(() => {})
|
||||||
},
|
},
|
||||||
handleModelSquareClick() {
|
handleModelSquareClick() {
|
||||||
this.closeProductPanelImmediate()
|
this.closeProductPanelImmediate()
|
||||||
|
|||||||
@ -247,38 +247,15 @@ export default Vue.extend({
|
|||||||
},
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
mounted() {
|
|
||||||
this.scrollToRouteAnchor()
|
|
||||||
},
|
|
||||||
watch: {
|
watch: {
|
||||||
'$route.fullPath'() {
|
'$route.fullPath'() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
if (this.scrollToRouteAnchor()) return
|
|
||||||
this.scrollHomeToTop()
|
this.scrollHomeToTop()
|
||||||
window.setTimeout(this.scrollHomeToTop, 0)
|
window.setTimeout(this.scrollHomeToTop, 0)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
scrollToRouteAnchor() {
|
|
||||||
const anchor = this.$route.query.anchor
|
|
||||||
if (!anchor || !this.$route.path.includes('/homePage/index')) return false
|
|
||||||
window.setTimeout(() => {
|
|
||||||
this.scrollToElementWithRetry(anchor)
|
|
||||||
}, 120)
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
scrollToElementWithRetry(id, attempt = 0) {
|
|
||||||
const element = document.getElementById(id)
|
|
||||||
if (element) {
|
|
||||||
element.scrollIntoView({ behavior: 'smooth', block: 'start' })
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if (attempt < 30) {
|
|
||||||
window.setTimeout(() => this.scrollToElementWithRetry(id, attempt + 1), 100)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
},
|
|
||||||
scrollHomeToTop() {
|
scrollHomeToTop() {
|
||||||
const container = this.$el
|
const container = this.$el
|
||||||
if (container) container.scrollTop = 0
|
if (container) container.scrollTop = 0
|
||||||
@ -358,11 +335,9 @@ export default Vue.extend({
|
|||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.homeOut {
|
.homeOut {
|
||||||
//padding-top: 60px;
|
//padding-top: 60px;
|
||||||
width: 100%;
|
|
||||||
min-width: 0;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow-x: hidden;
|
overflow: auto !important;
|
||||||
overflow-y: auto !important;
|
min-width: 1500px;
|
||||||
// background: linear-gradient(180deg, #f0f7ff 0%, #ffffff 60%, #f5f8ff 100%);
|
// background: linear-gradient(180deg, #f0f7ff 0%, #ffffff 60%, #f5f8ff 100%);
|
||||||
}
|
}
|
||||||
#topBox{
|
#topBox{
|
||||||
@ -375,7 +350,6 @@ export default Vue.extend({
|
|||||||
|
|
||||||
.home-router-view {
|
.home-router-view {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-width: 0;
|
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -570,8 +570,6 @@ export default {
|
|||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
.home-main-page {
|
.home-main-page {
|
||||||
width: 100%;
|
|
||||||
min-width: 0;
|
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background-color: #f0f7ff !important;
|
background-color: #f0f7ff !important;
|
||||||
background-image: linear-gradient(180deg, #f0f7ff 0%, #ffffff 60%, #f5f8ff 100%) !important;
|
background-image: linear-gradient(180deg, #f0f7ff 0%, #ffffff 60%, #f5f8ff 100%) !important;
|
||||||
@ -642,7 +640,7 @@ body.dark-theme .bg-orb {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 120px 5% 96px;
|
padding: 120px 24px 96px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -756,7 +754,7 @@ body.dark-theme .bg-orb {
|
|||||||
|
|
||||||
.ai-solution-section {
|
.ai-solution-section {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 60px 5% 110px;
|
padding: 60px 24px 110px;
|
||||||
scroll-margin-top: 90px;
|
scroll-margin-top: 90px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -1153,7 +1151,7 @@ body.dark-theme .bg-orb {
|
|||||||
|
|
||||||
.case-section {
|
.case-section {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 96px 5% 112px;
|
padding: 96px 24px 112px;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1359,7 +1357,7 @@ body.dark-theme .bg-orb {
|
|||||||
|
|
||||||
.news-section {
|
.news-section {
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 96px 5% 112px;
|
padding: 96px 24px 112px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,24 +6,24 @@
|
|||||||
<i class="el-icon-lock"></i>
|
<i class="el-icon-lock"></i>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3>{{ $t('loginDialog.resetPassword') }}</h3>
|
<h3>重置密码</h3>
|
||||||
<p>{{ $t('loginDialog.resetPasswordDesc') }}</p>
|
<p>通过手机号验证码验证身份后设置新密码</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-form ref="formRef" :model="form" :rules="rules" label-position="top" class="forgot-form" autocomplete="off">
|
<el-form ref="formRef" :model="form" :rules="rules" label-position="top" class="forgot-form" autocomplete="off">
|
||||||
<el-form-item :label="`* ${$t('loginDialog.mobileLabel')}`" prop="username">
|
<el-form-item label="手机号" prop="username">
|
||||||
<el-input v-model="form.username" clearable autocomplete="off" :placeholder="$t('loginDialog.enterBoundMobile')"></el-input>
|
<el-input v-model="form.username" clearable autocomplete="off" placeholder="请输入绑定手机号"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="`* ${$t('loginDialog.newPasswordLabel')}`" prop="password">
|
<el-form-item label="新密码" prop="password">
|
||||||
<el-input v-model="form.password" clearable show-password autocomplete="new-password"
|
<el-input v-model="form.password" clearable show-password autocomplete="new-password"
|
||||||
:placeholder="$t('loginDialog.enterNewPassword')"></el-input>
|
placeholder="请输入新密码"></el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item :label="`* ${$t('loginDialog.verificationCodeLabel')}`" prop="vcode">
|
<el-form-item label="验证码" prop="vcode">
|
||||||
<div class="code-row">
|
<div class="code-row">
|
||||||
<el-input v-model="form.vcode" clearable autocomplete="off" :placeholder="$t('loginDialog.enterVerificationCode')"></el-input>
|
<el-input v-model="form.vcode" clearable autocomplete="off" placeholder="请输入验证码"></el-input>
|
||||||
<el-button class="code-btn" :disabled="isDisabled || isGettingCode" :loading="isGettingCode"
|
<el-button class="code-btn" :disabled="isDisabled || isGettingCode" :loading="isGettingCode"
|
||||||
@click="debouncedGetCode">
|
@click="debouncedGetCode">
|
||||||
{{ sendCodeText }}
|
{{ sendCodeText }}
|
||||||
@ -33,8 +33,8 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
|
|
||||||
<div slot="footer" class="forgot-footer">
|
<div slot="footer" class="forgot-footer">
|
||||||
<el-button @click="handleClose">{{ $t('loginDialog.cancel') }}</el-button>
|
<el-button @click="handleClose">取消</el-button>
|
||||||
<el-button class="confirm-btn" type="primary" :loading="submitting" @click="handleSubmit">{{ $t('loginDialog.confirmReset') }}</el-button>
|
<el-button class="confirm-btn" type="primary" :loading="submitting" @click="handleSubmit">确认重置</el-button>
|
||||||
</div>
|
</div>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
@ -53,7 +53,15 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
form: this.createEmptyForm(),
|
form: this.createEmptyForm(),
|
||||||
sendCodeText: '',
|
rules: {
|
||||||
|
username: [
|
||||||
|
{ required: true, message: '请输入手机号', trigger: 'blur' },
|
||||||
|
{ pattern: /^1[3-9]\d{9}$/, message: '请输入正确的手机号', trigger: 'blur' }
|
||||||
|
],
|
||||||
|
password: [{ required: true, message: '请输入新密码', trigger: 'blur' }],
|
||||||
|
vcode: [{ required: true, message: '请输入验证码', trigger: 'blur' }]
|
||||||
|
},
|
||||||
|
sendCodeText: '获取验证码',
|
||||||
isDisabled: false,
|
isDisabled: false,
|
||||||
isGettingCode: false,
|
isGettingCode: false,
|
||||||
submitting: false,
|
submitting: false,
|
||||||
@ -62,36 +70,11 @@ export default {
|
|||||||
debounceTimer: null
|
debounceTimer: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
|
||||||
rules() {
|
|
||||||
return {
|
|
||||||
username: [
|
|
||||||
{ required: true, message: this.$t('loginDialog.mobileRequired'), trigger: 'blur' },
|
|
||||||
{ pattern: /^1[3-9]\d{9}$/, message: this.$t('loginDialog.mobileInvalid'), trigger: 'blur' }
|
|
||||||
],
|
|
||||||
password: [{ required: true, message: this.$t('loginDialog.newPasswordRequired'), trigger: 'blur' }],
|
|
||||||
vcode: [{ required: true, message: this.$t('loginDialog.codeRequired'), trigger: 'blur' }]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
'$i18n.locale'() {
|
|
||||||
this.resetCodeButtonText()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
created() {
|
|
||||||
this.resetCodeButtonText()
|
|
||||||
},
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
this.resetCodeState()
|
this.resetCodeState()
|
||||||
clearTimeout(this.debounceTimer)
|
clearTimeout(this.debounceTimer)
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
resetCodeButtonText() {
|
|
||||||
if (!this.isDisabled) {
|
|
||||||
this.sendCodeText = this.$t('loginDialog.getVerificationCode')
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleOpen() {
|
handleOpen() {
|
||||||
this.resetForm()
|
this.resetForm()
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
@ -127,7 +110,7 @@ export default {
|
|||||||
async getCode() {
|
async getCode() {
|
||||||
if (!this.form.username || !/^1[3-9]\d{9}$/.test(this.form.username)) {
|
if (!this.form.username || !/^1[3-9]\d{9}$/.test(this.form.username)) {
|
||||||
this.isGettingCode = false
|
this.isGettingCode = false
|
||||||
this.$message.error(this.$t('loginDialog.mobileInvalid'))
|
this.$message.error('请输入正确的手机号')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,13 +123,13 @@ export default {
|
|||||||
if (res.status === true) {
|
if (res.status === true) {
|
||||||
this.form.codeid = res.codeid
|
this.form.codeid = res.codeid
|
||||||
this.startCountdown()
|
this.startCountdown()
|
||||||
this.$message.success(this.$t('loginDialog.codeSentCheck'))
|
this.$message.success('验证码已发送,请注意查收。')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$message.error(res.msg || this.$t('loginDialog.codeSendFail'))
|
this.$message.error(res.msg || '验证码获取失败')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$message.error(this.$t('loginDialog.codeSendFail'))
|
this.$message.error('验证码获取失败')
|
||||||
} finally {
|
} finally {
|
||||||
this.isGettingCode = false
|
this.isGettingCode = false
|
||||||
}
|
}
|
||||||
@ -154,20 +137,20 @@ export default {
|
|||||||
startCountdown() {
|
startCountdown() {
|
||||||
this.timeCount = 59
|
this.timeCount = 59
|
||||||
this.isDisabled = true
|
this.isDisabled = true
|
||||||
this.sendCodeText = this.$t('loginDialog.resendCode', { seconds: this.timeCount })
|
this.sendCodeText = `重新发送${this.timeCount}s`
|
||||||
|
|
||||||
clearInterval(this.timer)
|
clearInterval(this.timer)
|
||||||
this.timer = setInterval(() => {
|
this.timer = setInterval(() => {
|
||||||
if (this.timeCount > 0) {
|
if (this.timeCount > 0) {
|
||||||
this.timeCount--
|
this.timeCount--
|
||||||
this.sendCodeText = this.$t('loginDialog.resendCode', { seconds: this.timeCount })
|
this.sendCodeText = `重新发送${this.timeCount}s`
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.resetCodeState()
|
this.resetCodeState()
|
||||||
}, 1000)
|
}, 1000)
|
||||||
},
|
},
|
||||||
resetCodeState() {
|
resetCodeState() {
|
||||||
this.sendCodeText = this.$t('loginDialog.getVerificationCode')
|
this.sendCodeText = '获取验证码'
|
||||||
clearInterval(this.timer)
|
clearInterval(this.timer)
|
||||||
this.timer = null
|
this.timer = null
|
||||||
this.isDisabled = false
|
this.isDisabled = false
|
||||||
@ -177,7 +160,7 @@ export default {
|
|||||||
this.$refs.formRef.validate(async valid => {
|
this.$refs.formRef.validate(async valid => {
|
||||||
if (!valid) return
|
if (!valid) return
|
||||||
if (!this.form.codeid) {
|
if (!this.form.codeid) {
|
||||||
this.$message.error(this.$t('loginDialog.getCodeFirst'))
|
this.$message.error('请先获取验证码')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -192,14 +175,14 @@ export default {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (res.status === true) {
|
if (res.status === true) {
|
||||||
this.$message.success(this.$t('loginDialog.resetSuccess'))
|
this.$message.success('密码重置成功')
|
||||||
this.handleClose()
|
this.handleClose()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$message.error(res.msg || this.$t('loginDialog.resetFail'))
|
this.$message.error(res.msg || '密码重置失败')
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.$message.error(this.$t('loginDialog.resetFail'))
|
this.$message.error('密码重置失败')
|
||||||
} finally {
|
} finally {
|
||||||
this.submitting = false
|
this.submitting = false
|
||||||
}
|
}
|
||||||
@ -267,14 +250,7 @@ export default {
|
|||||||
|
|
||||||
.forgot-form {
|
.forgot-form {
|
||||||
.el-form-item {
|
.el-form-item {
|
||||||
margin-bottom: 28px;
|
margin-bottom: 22px;
|
||||||
}
|
|
||||||
|
|
||||||
.el-form-item__error {
|
|
||||||
position: static;
|
|
||||||
margin-top: 6px;
|
|
||||||
padding-top: 0;
|
|
||||||
line-height: 1.4;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.el-form-item__label {
|
.el-form-item__label {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user