diff --git a/b/product/search_user_inquiry.dspy b/b/product/search_user_inquiry.dspy index a5ce76d..928e88e 100644 --- a/b/product/search_user_inquiry.dspy +++ b/b/product/search_user_inquiry.dspy @@ -55,26 +55,44 @@ 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) result = await sor.sqlExe(search_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;""" + dict_sql = """ + 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_mapping = {} + dict_mapping_zh = {} + dict_mapping_en = {} for dict_item in dict_result: dict_type = dict_item.get('dict_type') - dict_mapping.setdefault(dict_type, {})[str(dict_item.get('dict_key'))] = dict_item.get('dict_value') + dict_key = str(dict_item.get('dict_key')) + 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 = { + value_mapping_zh = { 'custom_type': {'0': '个人', '1': '企业'}, - 'enterprise_type': dict_mapping.get('enterprise_type', {}), - 'region': dict_mapping.get('region', {}), + 'enterprise_type': dict_mapping_zh.get('enterprise_type', {}), + 'region': dict_mapping_zh.get('region', {}), '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 key, mapping in value_mapping.items(): + for key in value_mapping_zh.keys(): if key in data_dic: - data_dic['%s_name' % key] = mapping.get(str(data_dic.get(key)), data_dic.get(key)) - direction_mapping = dict_mapping.get('direction', {}) + value_key = str(data_dic.get(key)) + data_dic['%s_name_zh' % key] = value_mapping_zh[key].get(value_key, data_dic.get(key)) + 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 [] - 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_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_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': # 创建映射字段 导出execl @@ -106,11 +124,11 @@ async def search_user_inquiry(ns={}): value = data_dic[key] chinese_key = field_mapping[key] if key == 'consult_direction': - direction_mapping = dict_mapping.get('direction', {}) + direction_mapping = dict_mapping_zh.get('direction', {}) 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()]) - elif key in value_mapping: - mapped_value = value_mapping[key].get(str(value), value) # 若未找到对应映射,保留原始值 + elif key in value_mapping_zh: + mapped_value = value_mapping_zh[key].get(str(value), value) # 若未找到对应映射,保留原始值 new_data_dic[chinese_key] = mapped_value else: new_data_dic[chinese_key] = value diff --git a/b/product/search_user_inquiry_dict.dspy b/b/product/search_user_inquiry_dict.dspy index c2b770d..7f3ee31 100644 --- a/b/product/search_user_inquiry_dict.dspy +++ b/b/product/search_user_inquiry_dict.dspy @@ -4,7 +4,12 @@ async def search_user_inquiry_dict(ns={}): where_sql = "where status = 1" if ns.get('dict_type'): where_sql += " and dict_type = '%s'" % ns.get('dict_type') - search_sql = """select * from product_inquiry_dict %s order by dict_type asc, sort_order asc;""" % where_sql + search_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, {}) return { 'status': True, diff --git a/docs/superpowers/plans/2026-08-07-bilingual-inquiry-dictionary.md b/docs/superpowers/plans/2026-08-07-bilingual-inquiry-dictionary.md new file mode 100644 index 0000000..6d258df --- /dev/null +++ b/docs/superpowers/plans/2026-08-07-bilingual-inquiry-dictionary.md @@ -0,0 +1,39 @@ +# 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`. diff --git a/docs/superpowers/specs/2026-08-07-bilingual-inquiry-dictionary-design.md b/docs/superpowers/specs/2026-08-07-bilingual-inquiry-dictionary-design.md new file mode 100644 index 0000000..655c38b --- /dev/null +++ b/docs/superpowers/specs/2026-08-07-bilingual-inquiry-dictionary-design.md @@ -0,0 +1,29 @@ +# 咨询字典双语接口设计 + +## 目标 + +咨询相关接口适配 `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 仍只输出中文显示值。 diff --git a/f/web-kboss/src/assets/less/news/news.less b/f/web-kboss/src/assets/less/news/news.less index a70e549..9d7ba55 100644 --- a/f/web-kboss/src/assets/less/news/news.less +++ b/f/web-kboss/src/assets/less/news/news.less @@ -2,7 +2,9 @@ position: relative; min-height: 100vh; overflow-x: hidden; + overflow-y: hidden; color: #1f2937; + padding: 0 12%; background: 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%), @@ -10,10 +12,10 @@ } .news-shell { - position: relative; + // position: relative; z-index: 1; - max-width: 1280px; - margin: 0 auto; + // max-width: 1280px; + // margin: 0 auto; padding: 0 24px; } @@ -55,9 +57,9 @@ } .news-hero { - position: relative; + // position: relative; padding: 140px 0 72px; - overflow: hidden; + // overflow: hidden; } .news-hero::before { @@ -93,6 +95,8 @@ } .hero-content { + text-align: left; + margin: 0 ; animation: fadeInUp 0.8s ease-out forwards; } @@ -197,6 +201,7 @@ .news-item { position: relative; overflow: hidden; + cursor: pointer; background: #fff; border: 1px solid rgba(0, 0, 0, 0.04); diff --git a/f/web-kboss/src/i18n/lang/en-US.js b/f/web-kboss/src/i18n/lang/en-US.js index 3514dc2..823fd09 100644 --- a/f/web-kboss/src/i18n/lang/en-US.js +++ b/f/web-kboss/src/i18n/lang/en-US.js @@ -401,5 +401,59 @@ export default { openedDecision: 'The Investment Strategy Agent 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 } diff --git a/f/web-kboss/src/i18n/lang/zh-CN.js b/f/web-kboss/src/i18n/lang/zh-CN.js index 09ec8bd..4925636 100644 --- a/f/web-kboss/src/i18n/lang/zh-CN.js +++ b/f/web-kboss/src/i18n/lang/zh-CN.js @@ -401,5 +401,59 @@ export default { openedDecision: '已为您打开投策智能体页面 📊
还有其他想了解的吗?', 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 } diff --git a/f/web-kboss/src/views/LoginDialog/LoginDialog.vue b/f/web-kboss/src/views/LoginDialog/LoginDialog.vue index ec5920c..707e64e 100644 --- a/f/web-kboss/src/views/LoginDialog/LoginDialog.vue +++ b/f/web-kboss/src/views/LoginDialog/LoginDialog.vue @@ -13,31 +13,31 @@
-

{{ activeTab === 'login' ? '欢迎登录' : '创建账号' }}

+

{{ activeTab === 'login' ? $t('loginDialog.welcomeLogin') : $t('loginDialog.createAccount') }}

- - + +
- - + +