diff --git a/b/bill/finance_settlement_create.dspy b/b/bill/finance_settlement_create.dspy
index cdb281d..35568a9 100644
--- a/b/bill/finance_settlement_create.dspy
+++ b/b/bill/finance_settlement_create.dspy
@@ -147,7 +147,7 @@ async def _fetch_source_rows(sor, args):
AND sd.accounting_orgid=${accounting_orgid}$
AND sd.del_flg='0'
AND sd.accounting_dir='贷'
- AND sd.subjectname LIKE '待结转%'
+ AND sd.subjectname LIKE '待结转%%'
"""
else:
filters.append('cust.parentid=${counterparty_orgid}$')
diff --git a/b/bill/finance_settlement_preview.dspy b/b/bill/finance_settlement_preview.dspy
index 131cb36..6089fc6 100644
--- a/b/bill/finance_settlement_preview.dspy
+++ b/b/bill/finance_settlement_preview.dspy
@@ -161,7 +161,7 @@ async def _fetch_source_rows(sor, args):
AND sd.accounting_orgid=${accounting_orgid}$
AND sd.del_flg='0'
AND sd.accounting_dir='贷'
- AND sd.subjectname LIKE '待结转%'
+ AND sd.subjectname LIKE '待结转%%'
"""
settlement_expr = 'COALESCE(sd.amount, 0)'
sale_mode_expr = 'sd.subjectname'
diff --git a/b/bill/finance_settlement_summary.dspy b/b/bill/finance_settlement_summary.dspy
index 9cf4987..feaf468 100644
--- a/b/bill/finance_settlement_summary.dspy
+++ b/b/bill/finance_settlement_summary.dspy
@@ -91,7 +91,7 @@ async def _fetch_source_rows(sor, args):
AND bd.accounting_orgid = ${accounting_orgid}$
AND bd.del_flg = '0'
AND bd.accounting_dir = '贷'
- AND bd.subjectname LIKE '待结转%'
+ AND bd.subjectname LIKE '待结转%%'
"""
if args.get('counterparty_orgid'):
filters.append('b.providerid = ${counterparty_orgid}$')
diff --git a/b/product/add_user_inquiry.dspy b/b/product/add_user_inquiry.dspy
index 88e0670..e09b03f 100644
--- a/b/product/add_user_inquiry.dspy
+++ b/b/product/add_user_inquiry.dspy
@@ -20,7 +20,11 @@ async def add_user_inquiry(ns={}):
'name': ns.get('name'),
'phone': ns.get('phone'),
'company': ns.get('company'),
- 'email': ns.get('email')
+ 'enterprise_type': ns.get('enterprise_type'),
+ 'region': ns.get('region'),
+ 'consult_direction': ns.get('consult_direction'),
+ 'email': ns.get('email'),
+ 'source': ns.get('source')
}
await sor.C('product_inquiry', ns_c)
return {
diff --git a/b/product/delete_user_inquiry.dspy b/b/product/delete_user_inquiry.dspy
index eecdbb5..415735f 100644
--- a/b/product/delete_user_inquiry.dspy
+++ b/b/product/delete_user_inquiry.dspy
@@ -1,13 +1,37 @@
async def delete_user_inquiry(ns={}):
db = DBPools()
async with db.sqlorContext('kboss') as sor:
- ns_c = {
- 'id': ns.get('id')
- }
- await sor.D('product_inquiry', ns_c)
+ ids = ns.get('ids') or ns.get('id')
+ if not ids:
+ return {
+ 'status': False,
+ 'msg': '请传递id'
+ }
+ if isinstance(ids, str):
+ if '[' in ids:
+ ids = ids.replace("'", '"')
+ ids = json.loads(ids)
+ elif ',' in ids:
+ ids = ids.replace('"', '').replace("'", '').split(',')
+ else:
+ ids = [ids]
+
+ delete_count = 0
+ for inquiry_id in ids:
+ if not inquiry_id:
+ continue
+ ns_c = {
+ 'id': inquiry_id
+ }
+ await sor.D('product_inquiry', ns_c)
+ delete_count += 1
+
return {
'status': True,
- 'msg': 'delete success'
+ 'msg': 'delete success',
+ 'data': {
+ 'delete_count': delete_count
+ }
}
ret = await delete_user_inquiry(params_kw)
diff --git a/b/product/search_user_inquiry.dspy b/b/product/search_user_inquiry.dspy
index 906e50e..a5ce76d 100644
--- a/b/product/search_user_inquiry.dspy
+++ b/b/product/search_user_inquiry.dspy
@@ -10,8 +10,72 @@ async def search_user_inquiry(ns={}):
db = DBPools()
async with db.sqlorContext('kboss') as sor:
- search_sql = """select * from product_inquiry where domain_name = '%s' and del_flg = '0' order by update_time desc;""" % domain_name
+ where_conditions = ["domain_name = '%s'" % domain_name, "del_flg = '0'"]
+ if ns.get('name'):
+ where_conditions.append("name like '%%%%%s%%%%'" % ns.get('name'))
+ if ns.get('phone'):
+ where_conditions.append("phone like '%%%%%s%%%%'" % ns.get('phone'))
+ if ns.get('email'):
+ where_conditions.append("email like '%%%%%s%%%%'" % ns.get('email'))
+ if ns.get('source'):
+ if ns.get('source') == '未知':
+ where_conditions.append("(source is null or source = '')")
+ else:
+ where_conditions.append("source = '%s'" % ns.get('source'))
+ if ns.get('feedback'):
+ where_conditions.append("feedback = '%s'" % ns.get('feedback'))
+ where_clause = ' and '.join(where_conditions)
+
+ # 分页参数
+ page = int(ns.get('page', 1))
+ page_size = int(ns.get('page_size', 20))
+ offset = (page - 1) * page_size
+
+ # 统计查询(基于全部符合条件的数据)
+ count_sql = """select count(*) as cnt from product_inquiry where %s""" % where_clause
+ total_count = (await sor.sqlExe(count_sql, {}))[0]['cnt']
+
+ source_sql = """select source, count(*) as cnt from product_inquiry where %s group by source""" % where_clause
+ source_result = await sor.sqlExe(source_sql, {})
+ source_stats = {}
+ for row in source_result:
+ src = row.get('source') or '未知'
+ source_stats[src] = row.get('cnt')
+
+ pending_sql = """select count(*) as cnt from product_inquiry where %s and feedback = '0'""" % where_clause
+ pending_count = (await sor.sqlExe(pending_sql, {}))[0]['cnt']
+
+ source_list_sql = """select distinct source from product_inquiry where %s""" % where_clause
+ source_list = [row['source'] for row in (await sor.sqlExe(source_list_sql, {}))]
+ has_empty_source = any(s is None or s == '' for s in source_list)
+ source_list = [s for s in source_list if s] # 过滤空值
+ if has_empty_source:
+ source_list.append('未知')
+
+ # 分页查询
+ 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_result = await sor.sqlExe(dict_sql, {})
+ dict_mapping = {}
+ 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')
+
+ value_mapping = {
+ 'custom_type': {'0': '个人', '1': '企业'},
+ 'enterprise_type': dict_mapping.get('enterprise_type', {}),
+ 'region': dict_mapping.get('region', {}),
+ 'feedback': {'0': '待回复', '1': '已回复'}
+ }
+ for data_dic in result:
+ for key, mapping in value_mapping.items():
+ 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', {})
+ 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()])
+
if ns.get('to_excel') == '1':
# 创建映射字段 导出execl
# 结果转换成 中文名称:值 的字典列表
@@ -21,14 +85,15 @@ async def search_user_inquiry(ns={}):
'phone': '联系人电话',
'email': '邮箱',
'company': '公司名称',
+ 'enterprise_type': '企业类型',
+ 'region': '所在区域',
+ 'consult_direction': '咨询方向',
'content': '咨询内容',
'feedback': '反馈状态',
+ 'remark': '备注',
+ 'create_at': '创建时间'
}
# 新增值映射字典,集中管理各字段的数值转换规则
- value_mapping = {
- 'custom_type': {'0': '个人', '1': '企业'},
- 'feedback': {'0': '未反馈', '1': '已反馈'} # 根据表结构补充反馈状态映射
- }
# 转换字典键为中文
for data_dic in result:
# 拆分后:显式循环结构(便于后续处理)
@@ -40,7 +105,11 @@ async def search_user_inquiry(ns={}):
continue
value = data_dic[key]
chinese_key = field_mapping[key]
- if key in value_mapping:
+ if key == 'consult_direction':
+ direction_mapping = dict_mapping.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) # 若未找到对应映射,保留原始值
new_data_dic[chinese_key] = mapped_value
else:
@@ -51,7 +120,14 @@ async def search_user_inquiry(ns={}):
return {
'status': True,
'msg': 'search success',
- 'data': result
+ 'data': result,
+ 'total_count': total_count,
+ 'source_stats': source_stats,
+ 'pending_count': pending_count,
+ 'source_list': source_list,
+ 'page': page,
+ 'page_size': page_size,
+ 'feedback_list': [{'id': 0, 'name': '待回复'},{'id': 1, 'name': '已回复'}]
}
ret = await search_user_inquiry(params_kw)
diff --git a/b/product/search_user_inquiry_dict.dspy b/b/product/search_user_inquiry_dict.dspy
new file mode 100644
index 0000000..610e410
--- /dev/null
+++ b/b/product/search_user_inquiry_dict.dspy
@@ -0,0 +1,16 @@
+async def search_user_inquiry_dict(ns={}):
+ db = DBPools()
+ async with db.sqlorContext('kboss') as sor:
+ where_sql = "where status = 1"
+ if ns.get('dict_type'):
+ where_sql += " and dict_type = '%s'" % ns.get('dict_type')
+ search_sql = """select id, dict_type, dict_key, dict_value, 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,
+ 'msg': 'search success',
+ 'data': result
+ }
+
+ret = await search_user_inquiry_dict(params_kw)
+return ret
diff --git a/b/product/update_user_inquiry.dspy b/b/product/update_user_inquiry.dspy
index 9e43c5f..e3a9cbc 100644
--- a/b/product/update_user_inquiry.dspy
+++ b/b/product/update_user_inquiry.dspy
@@ -1,14 +1,40 @@
async def update_user_inquiry(ns={}):
db = DBPools()
async with db.sqlorContext('kboss') as sor:
- ns_c = {
- 'id': ns.get('id'),
- 'feedback': ns.get('feedback')
- }
- await sor.U('product_inquiry', ns_c)
+ ids = ns.get('ids') or ns.get('id')
+ if not ids:
+ return {
+ 'status': False,
+ 'msg': '请传递id'
+ }
+ if isinstance(ids, str):
+ if ids.startswith('['):
+ ids = json.loads(ids)
+ elif ',' in ids:
+ ids = ids.replace('"', '').replace("'", '').split(',')
+ else:
+ ids = [ids]
+
+ update_count = 0
+ for inquiry_id in ids:
+ if not inquiry_id:
+ continue
+ ns_c = {
+ 'id': inquiry_id
+ }
+ if 'feedback' in ns:
+ ns_c['feedback'] = ns.get('feedback')
+ if 'remark' in ns:
+ ns_c['remark'] = ns.get('remark')
+ await sor.U('product_inquiry', ns_c)
+ update_count += 1
+
return {
'status': True,
- 'msg': 'update success'
+ 'msg': 'update success',
+ 'data': {
+ 'update_count': update_count
+ }
}
ret = await update_user_inquiry(params_kw)
diff --git a/b/user_inquiry.txt b/b/user_inquiry.txt
new file mode 100644
index 0000000..a594ec0
--- /dev/null
+++ b/b/user_inquiry.txt
@@ -0,0 +1,43 @@
+CREATE TABLE `product_inquiry` (
+ `id` varchar(32) NOT NULL COMMENT '唯一标识符',
+ `domain_name` varchar(64) NOT NULL COMMENT '所属域名',
+ `publish_type` varchar(1) DEFAULT NULL COMMENT '发布商品1/ 发布需求2',
+ `relate_id` varchar(32) DEFAULT NULL COMMENT '发布商品1/ 发布需求2',
+ `content` varchar(1024) DEFAULT NULL COMMENT '咨询需求内容',
+ `custom_type` tinyint(1) DEFAULT NULL COMMENT '客户类型(0-个人/1-企业)',
+ `name` varchar(50) DEFAULT NULL COMMENT '联系人姓名',
+ `phone` varchar(20) DEFAULT NULL COMMENT '联系电话',
+ `company` varchar(100) DEFAULT NULL COMMENT '企业客户公司名称',
+ `enterprise_type` tinyint(1) DEFAULT NULL COMMENT '企业类型(1-大型/2-中小企业/3-OPC个人/4-高校科研机构/5-政府/6-其他)',
+ `region` tinyint(1) DEFAULT NULL COMMENT '所在区域(0-大陆/1-港澳台)',
+ `consult_direction` varchar(20) DEFAULT NULL COMMENT '咨询方向(多选用逗号分隔:1,2,3)',
+ `email` varchar(50) DEFAULT NULL COMMENT '电子邮箱',
+ `feedback` varchar(1) DEFAULT '0' COMMENT '反馈状态',
+ `del_flg` varchar(1) DEFAULT '0' COMMENT '删除标志(0-正常/1-已删除)',
+ `update_time` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp() COMMENT '更新时间',
+ `create_at` timestamp NULL DEFAULT current_timestamp() COMMENT '创建时间',
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci ROW_FORMAT=DYNAMIC COMMENT='产品咨询表';
+
+CREATE TABLE `product_inquiry_dict` (
+ `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+ `dict_type` varchar(30) NOT NULL COMMENT '字典类型(标识属于哪一组选项)',
+ `dict_key` tinyint(4) NOT NULL COMMENT '字典键值(对应数据库实际存储的数字)',
+ `dict_value` varchar(50) NOT NULL COMMENT '字典显示名称(前端下拉框展示的文字)',
+ `sort_order` int(11) DEFAULT 0 COMMENT '排序序号(数字越小越靠前)',
+ `status` tinyint(1) DEFAULT 1 COMMENT '状态(0-禁用/1-启用)',
+ `create_time` timestamp NOT NULL DEFAULT current_timestamp() COMMENT '创建时间',
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='咨询表字典配置表(运营可维护)';
+product_inquiry_dict表相关数据:
+1 enterprise_type 1 大型企业 1 1 2026-07-07 16:32:45
+2 enterprise_type 2 中小企业 2 1 2026-07-07 16:32:45
+3 enterprise_type 3 OPC个人 3 1 2026-07-07 16:32:45
+4 enterprise_type 4 高校科研机构 4 1 2026-07-07 16:32:45
+5 enterprise_type 5 政府 5 1 2026-07-07 16:32:45
+6 enterprise_type 6 其他 6 1 2026-07-07 16:32:45
+7 region 0 大陆 1 1 2026-07-07 16:34:02
+8 region 1 港澳台 2 1 2026-07-07 16:34:02
+9 direction 1 AI Infra 基础设施(云/网/算) 1 1 2026-07-07 16:34:02
+10 direction 2 AI Agent 智能体(产品开发) 2 1 2026-07-07 16:34:02
+11 direction 3 AI Builder 炼智师(能力提升培训) 3 1 2026-07-07 16:34:02
\ No newline at end of file
diff --git a/docs/财务结算中心.html b/docs/财务结算中心.html
new file mode 100644
index 0000000..fec7c97
--- /dev/null
+++ b/docs/财务结算中心.html
@@ -0,0 +1,800 @@
+
+
+
+
+
+ 财务结算中心
+
+
+
+
+
+
+
Finance Settlement Console
+
财务结算中心
+
+ 面向供应商与分销商的日结、月结费用查询和结算处理页面。支持汇总查询、账单预览、结算单创建、审批提交、审批回调和结算单追踪。
+
+
+
+
+ 接口状态
+ Ready
+
+
+ 当前模式
+ 供应商 / 日结
+
+
+
+
+
+
+
+
+
+
+
+
结算数据
+ 等待查询
+
+
+
+
+
+
+
+
+
+
+
+ | 提示 |
+
+
+
+
+ | 请先执行查询 |
+
+
+
+
+
+ 暂无数据
+
+
+
+
+
+
+
diff --git a/f/web-kboss/package.json b/f/web-kboss/package.json
index c8d672e..8aa16f7 100644
--- a/f/web-kboss/package.json
+++ b/f/web-kboss/package.json
@@ -14,7 +14,10 @@
"new": "plop",
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
"test:unit": "jest --clearCache && vue-cli-service test:unit",
- "test:ci": "npm run lint && npm run test:unit"
+ "test:ci": "npm run lint && npm run test:unit",
+ "i18n:extract": "node scripts/i18n-extract.js --dir src/views/homePage",
+ "i18n:extract:all": "node scripts/i18n-extract.js --dir src",
+ "i18n:replace:home": "node scripts/i18n-extract.js --dir src/views/homePage --replace"
},
"dependencies": {
"@form-create/element-ui": "^2.5.30",
@@ -55,6 +58,7 @@
"vue-count-to": "^1.0.13",
"vue-cropper": "^0.6.5",
"vue-device-detector": "^1.1.6",
+ "vue-i18n": "^8.28.2",
"vue-infinite-scroll": "^2.0.2",
"vue-router": "^3.0.2",
"vue-splitpane": "1.0.4",
@@ -87,7 +91,7 @@
"eslint-plugin-vue": "6.2.2",
"html-webpack-plugin": "3.2.0",
"husky": "1.3.1",
- "less": "^3.9.0",
+ "less": "^3.13.1",
"less-loader": "^4.1.0",
"lint-staged": "8.1.5",
"mockjs": "1.0.1-beta3",
diff --git a/f/web-kboss/scripts/i18n-extract.js b/f/web-kboss/scripts/i18n-extract.js
new file mode 100644
index 0000000..f8fbc81
--- /dev/null
+++ b/f/web-kboss/scripts/i18n-extract.js
@@ -0,0 +1,191 @@
+/* eslint-disable no-console */
+const fs = require('fs')
+const path = require('path')
+
+const projectRoot = process.cwd()
+const args = process.argv.slice(2)
+
+const getArg = (name, defaultValue = '') => {
+ const full = `--${name}`
+ const hit = args.find((item) => item.startsWith(`${full}=`))
+ if (hit) return hit.slice(full.length + 1)
+ const idx = args.indexOf(full)
+ if (idx !== -1 && args[idx + 1]) return args[idx + 1]
+ return defaultValue
+}
+
+const hasFlag = (flag) => args.includes(`--${flag}`)
+
+const targetDirArg = getArg('dir', 'src/views/homePage')
+const replaceMode = hasFlag('replace')
+
+const targetDir = path.resolve(projectRoot, targetDirArg)
+const zhAutoPath = path.resolve(projectRoot, 'src/i18n/lang/zh-CN.auto.json')
+const enAutoPath = path.resolve(projectRoot, 'src/i18n/lang/en-US.auto.json')
+
+const chinesePattern = /[\u4e00-\u9fa5]/
+const ignorePattern = /^(\s*|[-:,.(){}\[\]/\\]+)$/
+
+const readJsonSafe = (filePath) => {
+ if (!fs.existsSync(filePath)) return {}
+ try {
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'))
+ } catch (error) {
+ console.warn(`[warn] JSON parse failed: ${filePath}`)
+ return {}
+ }
+}
+
+const writeJson = (filePath, value) => {
+ const content = JSON.stringify(value, null, 2) + '\n'
+ fs.writeFileSync(filePath, content, 'utf8')
+}
+
+const walkFiles = (dir, bucket) => {
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
+ entries.forEach((entry) => {
+ const fullPath = path.join(dir, entry.name)
+ if (entry.isDirectory()) {
+ if (['node_modules', '.git', 'dist'].includes(entry.name)) return
+ walkFiles(fullPath, bucket)
+ return
+ }
+ if (!/\.(vue|js)$/.test(entry.name)) return
+ bucket.push(fullPath)
+ })
+}
+
+const normalizeText = (text) =>
+ text
+ .replace(/\s+/g, ' ')
+ .replace(/ /g, ' ')
+ .trim()
+
+const keyFromText = (text) => {
+ let hash = 0
+ for (let i = 0; i < text.length; i += 1) {
+ hash = (hash * 131 + text.charCodeAt(i)) >>> 0
+ }
+ return `auto.k_${hash.toString(16)}`
+}
+
+const zhMessages = readJsonSafe(zhAutoPath)
+const enMessages = readJsonSafe(enAutoPath)
+
+const reverseMap = new Map()
+Object.keys(zhMessages).forEach((key) => {
+ reverseMap.set(zhMessages[key], key)
+})
+
+const ensureKey = (rawText) => {
+ const text = normalizeText(rawText)
+ if (!text || !chinesePattern.test(text) || ignorePattern.test(text)) return null
+
+ if (reverseMap.has(text)) return reverseMap.get(text)
+
+ let key = keyFromText(text)
+ while (zhMessages[key] && zhMessages[key] !== text) {
+ key = `${key}_${Math.floor(Math.random() * 10000)}`
+ }
+
+ zhMessages[key] = text
+ if (!Object.prototype.hasOwnProperty.call(enMessages, key)) {
+ enMessages[key] = ''
+ }
+ reverseMap.set(text, key)
+ return key
+}
+
+const transformTemplate = (template) => {
+ let replacedCount = 0
+
+ const textNodeRegex = />([^<>{}\n]*[\u4e00-\u9fa5][^<>{}\n]*) {
+ const key = ensureKey(inner)
+ if (!key || !replaceMode) return full
+ replacedCount += 1
+ return `>{{ $t('${key}') }}<`
+ })
+
+ const attrRegex = /\s([a-zA-Z_][\w-]*)=(["'])([^"']*[\u4e00-\u9fa5][^"']*)\2/g
+ updated = updated.replace(attrRegex, (full, attr, quote, value) => {
+ const key = ensureKey(value)
+ if (!key || !replaceMode) return full
+ replacedCount += 1
+ return ` :${attr}="$t('${key}')"`
+ })
+
+ return { updated, replacedCount }
+}
+
+const processVueFile = (filePath) => {
+ const raw = fs.readFileSync(filePath, 'utf8')
+ const templateMatch = raw.match(/([\s\S]*?)<\/template>/)
+ if (!templateMatch) return { changed: false, replacedCount: 0 }
+
+ const templateBlock = templateMatch[0]
+ const templateInner = templateMatch[1]
+
+ const beforeCount = Object.keys(zhMessages).length
+ const { updated, replacedCount } = transformTemplate(templateInner)
+ const afterCount = Object.keys(zhMessages).length
+ const extractedCount = afterCount - beforeCount
+
+ if (!replaceMode || replacedCount === 0) {
+ return { changed: false, replacedCount: 0, extractedCount }
+ }
+
+ const replacedBlock = `${updated}`
+ const next = raw.replace(templateBlock, replacedBlock)
+
+ if (next !== raw) {
+ fs.writeFileSync(filePath, next, 'utf8')
+ return { changed: true, replacedCount, extractedCount }
+ }
+ return { changed: false, replacedCount: 0, extractedCount }
+}
+
+const processJsLiterals = (filePath) => {
+ const raw = fs.readFileSync(filePath, 'utf8')
+ const stringRegex = /(['"`])([^'"`\n]*[\u4e00-\u9fa5][^'"`\n]*)\1/g
+ let match = stringRegex.exec(raw)
+ while (match) {
+ ensureKey(match[2])
+ match = stringRegex.exec(raw)
+ }
+}
+
+if (!fs.existsSync(targetDir)) {
+ console.error(`[error] Directory does not exist: ${targetDirArg}`)
+ process.exit(1)
+}
+
+const files = []
+walkFiles(targetDir, files)
+
+let changedFiles = 0
+let replacedEntries = 0
+let extractedEntries = 0
+
+files.forEach((filePath) => {
+ if (filePath.endsWith('.vue')) {
+ const result = processVueFile(filePath)
+ if (result.changed) changedFiles += 1
+ replacedEntries += result.replacedCount || 0
+ extractedEntries += result.extractedCount || 0
+ return
+ }
+ processJsLiterals(filePath)
+})
+
+writeJson(zhAutoPath, zhMessages)
+writeJson(enAutoPath, enMessages)
+
+console.log(`[i18n] target: ${targetDirArg}`)
+console.log(`[i18n] files scanned: ${files.length}`)
+console.log(`[i18n] new keys extracted: ${extractedEntries}`)
+console.log(`[i18n] replace mode: ${replaceMode ? 'on' : 'off'}`)
+console.log(`[i18n] files changed: ${changedFiles}`)
+console.log(`[i18n] nodes replaced: ${replacedEntries}`)
+console.log(`[i18n] zh map: src/i18n/lang/zh-CN.auto.json`)
+console.log(`[i18n] en map: src/i18n/lang/en-US.auto.json`)
diff --git a/f/web-kboss/src/api/H5/index.js b/f/web-kboss/src/api/H5/index.js
index cd5a6f9..4ffeb0c 100644
--- a/f/web-kboss/src/api/H5/index.js
+++ b/f/web-kboss/src/api/H5/index.js
@@ -53,3 +53,16 @@ export function reqCompany(data) {
data
})
}
+
+
+// 咨询表单选项
+export const reqConsultForm = (data) => {
+ return request({
+ url: '/product/search_user_inquiry_dict.dspy',
+ method: 'get',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ params: data
+ })
+}
\ No newline at end of file
diff --git a/f/web-kboss/src/api/ncmatch/index.js b/f/web-kboss/src/api/ncmatch/index.js
index 587f4d7..587a96b 100644
--- a/f/web-kboss/src/api/ncmatch/index.js
+++ b/f/web-kboss/src/api/ncmatch/index.js
@@ -163,6 +163,25 @@ export function reqApproveUserSearch(data){
})
}
+// 咨询表单状态切换
+export function reqUserInquiryStatusSwitch(data){
+ return request({
+ url: '/product/update_user_inquiry.dspy',
+ method: 'get',
+ headers: { 'Content-Type': 'application/json' },
+ params: data
+ })
+}
+// 咨询表单删除(批量 单个)
+export function reqUserInquiryDelete(data){
+ return request({
+ url: '/product/delete_user_inquiry.dspy',
+ method: 'get',
+ headers: { 'Content-Type': 'application/json' },
+ params: data
+ })
+}
+
//政企审核 更新 /user/enterprise_audit_info_update.dspy
export function reqEnterpriseUpdate(data){
diff --git a/f/web-kboss/src/assets/css/iconfont/demo_index.html b/f/web-kboss/src/assets/css/iconfont/demo_index.html
index 2357ca4..6c4feff 100644
--- a/f/web-kboss/src/assets/css/iconfont/demo_index.html
+++ b/f/web-kboss/src/assets/css/iconfont/demo_index.html
@@ -54,6 +54,24 @@
+ -
+
+
右箭头
+ 
+
+
+ -
+
+
上
+ 
+
+
+ -
+
+
下
+ 
+
+
-
购物车空
@@ -156,9 +174,9 @@
@font-face {
font-family: 'iconfont';
- src: url('iconfont.woff2?t=1781579680075') format('woff2'),
- url('iconfont.woff?t=1781579680075') format('woff'),
- url('iconfont.ttf?t=1781579680075') format('truetype');
+ src: url('iconfont.woff2?t=1782877614448') format('woff2'),
+ url('iconfont.woff?t=1782877614448') format('woff'),
+ url('iconfont.ttf?t=1782877614448') format('truetype');
}
第二步:定义使用 iconfont 的样式
@@ -184,6 +202,33 @@
+ -
+
+
+ 右箭头
+
+ .icon-youjiantou
+
+
+
+ -
+
+
+ 上
+
+ .icon-shang
+
+
+
+ -
+
+
+ 下
+
+ .icon-xia
+
+
+
-
@@ -337,6 +382,30 @@
+ -
+
+
右箭头
+ #icon-youjiantou
+
+
+ -
+
+
上
+ #icon-shang
+
+
+ -
+
+
下
+ #icon-xia
+
+
-