main #134

Merged
charles merged 49 commits from main into prod 2026-07-10 17:41:19 +08:00
69 changed files with 11008 additions and 2949 deletions

View File

@ -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}$')

View File

@ -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'

View File

@ -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}$')

View File

@ -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 {

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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)

43
b/user_inquiry.txt Normal file
View File

@ -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

View File

@ -0,0 +1,800 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>财务结算中心</title>
<style>
:root {
--primary: #246bfe;
--primary-soft: #e9f0ff;
--cyan: #00a9d6;
--green: #0aa66a;
--orange: #f59e0b;
--red: #ef4444;
--text: #1f2937;
--muted: #667085;
--line: #dbe7ff;
--panel: rgba(255, 255, 255, 0.88);
--bg: #f5f9ff;
--shadow: 0 18px 50px rgba(36, 107, 254, 0.12);
}
* {
box-sizing: border-box;
}
body {
margin: 0;
min-height: 100vh;
color: var(--text);
font-family: "Inter", "PingFang SC", "Microsoft YaHei", Arial, sans-serif;
background:
radial-gradient(circle at 12% 10%, rgba(36, 107, 254, 0.14), transparent 30%),
radial-gradient(circle at 85% 8%, rgba(0, 169, 214, 0.13), transparent 28%),
linear-gradient(135deg, #f7fbff 0%, #eef6ff 48%, #ffffff 100%);
}
body::before {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
opacity: 0.58;
background-image:
linear-gradient(rgba(36, 107, 254, 0.08) 1px, transparent 1px),
linear-gradient(90deg, rgba(36, 107, 254, 0.08) 1px, transparent 1px);
background-size: 28px 28px;
mask-image: linear-gradient(to bottom, black, transparent 75%);
}
.page {
position: relative;
width: min(1440px, calc(100% - 40px));
margin: 0 auto;
padding: 28px 0 44px;
}
.hero {
display: grid;
grid-template-columns: 1.4fr 0.8fr;
gap: 20px;
align-items: stretch;
margin-bottom: 20px;
}
.hero-card,
.panel,
.metric-card {
border: 1px solid rgba(145, 178, 255, 0.46);
border-radius: 22px;
background: var(--panel);
box-shadow: var(--shadow);
backdrop-filter: blur(16px);
}
.hero-card {
position: relative;
overflow: hidden;
padding: 30px;
}
.hero-card::after {
content: "";
position: absolute;
right: -80px;
top: -80px;
width: 240px;
height: 240px;
border-radius: 50%;
background: radial-gradient(circle, rgba(36, 107, 254, 0.18), transparent 68%);
}
.eyebrow {
display: inline-flex;
gap: 8px;
align-items: center;
padding: 7px 12px;
border: 1px solid rgba(36, 107, 254, 0.18);
border-radius: 999px;
color: var(--primary);
background: rgba(36, 107, 254, 0.08);
font-size: 13px;
font-weight: 700;
}
.pulse {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--green);
box-shadow: 0 0 0 6px rgba(10, 166, 106, 0.14);
}
h1 {
margin: 18px 0 10px;
font-size: clamp(30px, 4vw, 48px);
letter-spacing: -1px;
}
.hero p {
margin: 0;
max-width: 760px;
color: var(--muted);
line-height: 1.8;
}
.hero-side {
padding: 24px;
display: grid;
gap: 14px;
}
.status-chip {
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 16px;
border-radius: 16px;
background: linear-gradient(135deg, rgba(36, 107, 254, 0.08), rgba(255, 255, 255, 0.88));
border: 1px solid rgba(36, 107, 254, 0.12);
}
.status-chip strong {
font-size: 20px;
color: var(--primary);
}
.metrics {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 16px;
margin-bottom: 20px;
}
.metric-card {
padding: 18px;
min-height: 116px;
}
.metric-label {
color: var(--muted);
font-size: 13px;
}
.metric-value {
margin-top: 12px;
font-size: 28px;
font-weight: 800;
color: var(--primary);
word-break: break-all;
}
.metric-foot {
margin-top: 8px;
color: var(--muted);
font-size: 12px;
}
.layout {
display: grid;
grid-template-columns: 380px 1fr;
gap: 20px;
}
.panel {
padding: 20px;
}
.panel-title {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 16px;
}
.panel-title h2 {
margin: 0;
font-size: 18px;
}
.badge {
padding: 5px 10px;
border-radius: 999px;
color: var(--primary);
background: var(--primary-soft);
font-size: 12px;
font-weight: 700;
}
.form-grid {
display: grid;
gap: 14px;
}
.field {
display: grid;
gap: 7px;
}
label {
color: #344054;
font-size: 13px;
font-weight: 700;
}
input,
select {
width: 100%;
height: 42px;
border: 1px solid var(--line);
border-radius: 12px;
outline: none;
padding: 0 12px;
color: var(--text);
background: rgba(255, 255, 255, 0.92);
transition: 0.18s ease;
}
input:focus,
select:focus {
border-color: var(--primary);
box-shadow: 0 0 0 4px rgba(36, 107, 254, 0.12);
}
.two {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.actions {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-top: 6px;
}
button {
height: 42px;
border: 0;
border-radius: 12px;
cursor: pointer;
color: #fff;
background: linear-gradient(135deg, var(--primary), #4f8cff);
font-weight: 800;
box-shadow: 0 10px 24px rgba(36, 107, 254, 0.22);
transition: transform 0.18s ease, box-shadow 0.18s ease;
}
button:hover {
transform: translateY(-1px);
box-shadow: 0 14px 30px rgba(36, 107, 254, 0.28);
}
button.secondary {
color: var(--primary);
border: 1px solid rgba(36, 107, 254, 0.22);
background: #fff;
box-shadow: none;
}
button.green {
background: linear-gradient(135deg, var(--green), #32c28a);
}
button.orange {
background: linear-gradient(135deg, var(--orange), #fbbf24);
}
.tabs {
display: flex;
gap: 10px;
flex-wrap: wrap;
margin-bottom: 16px;
}
.tab {
padding: 10px 14px;
border: 1px solid var(--line);
border-radius: 999px;
color: var(--muted);
background: #fff;
cursor: pointer;
font-size: 13px;
font-weight: 800;
}
.tab.active {
color: #fff;
background: linear-gradient(135deg, var(--primary), var(--cyan));
border-color: transparent;
}
.table-wrap {
overflow: auto;
border: 1px solid rgba(145, 178, 255, 0.38);
border-radius: 16px;
background: #fff;
}
table {
width: 100%;
min-width: 980px;
border-collapse: collapse;
}
th,
td {
padding: 13px 14px;
text-align: left;
border-bottom: 1px solid #edf2ff;
font-size: 13px;
white-space: nowrap;
}
th {
position: sticky;
top: 0;
z-index: 1;
color: #31507a;
background: linear-gradient(180deg, #f6f9ff, #ffffff);
font-weight: 900;
}
tr:hover td {
background: #f8fbff;
}
.tag {
display: inline-flex;
padding: 4px 9px;
border-radius: 999px;
color: var(--primary);
background: var(--primary-soft);
font-size: 12px;
font-weight: 800;
}
.log {
min-height: 170px;
max-height: 340px;
overflow: auto;
padding: 14px;
border: 1px solid rgba(145, 178, 255, 0.38);
border-radius: 16px;
background: #fbfdff;
color: #344054;
font-family: Consolas, Monaco, monospace;
font-size: 12px;
line-height: 1.7;
white-space: pre-wrap;
}
.hint {
margin-top: 12px;
color: var(--muted);
font-size: 12px;
line-height: 1.7;
}
@media (max-width: 1100px) {
.hero,
.layout,
.metrics {
grid-template-columns: 1fr;
}
}
</style>
</head>
<body>
<main class="page">
<section class="hero">
<div class="hero-card">
<span class="eyebrow"><span class="pulse"></span> Finance Settlement Console</span>
<h1>财务结算中心</h1>
<p>
面向供应商与分销商的日结、月结费用查询和结算处理页面。支持汇总查询、账单预览、结算单创建、审批提交、审批回调和结算单追踪。
</p>
</div>
<div class="hero-card hero-side">
<div class="status-chip">
<span>接口状态</span>
<strong id="apiStatus">Ready</strong>
</div>
<div class="status-chip">
<span>当前模式</span>
<strong id="modeText">供应商 / 日结</strong>
</div>
</div>
</section>
<section class="metrics">
<div class="metric-card">
<div class="metric-label">销售金额</div>
<div class="metric-value" id="salesAmount">0.00000000</div>
<div class="metric-foot">sales_amount</div>
</div>
<div class="metric-card">
<div class="metric-label">结算金额</div>
<div class="metric-value" id="settlementAmount">0.00000000</div>
<div class="metric-foot">settlement_amount</div>
</div>
<div class="metric-card">
<div class="metric-label">平台收入</div>
<div class="metric-value" id="platformIncomeAmount">0.00000000</div>
<div class="metric-foot">platform_income_amount</div>
</div>
<div class="metric-card">
<div class="metric-label">账单数量</div>
<div class="metric-value" id="billCount">0</div>
<div class="metric-foot">bill_count</div>
</div>
</section>
<section class="layout">
<aside class="panel">
<div class="panel-title">
<h2>查询条件</h2>
<span class="badge">Light Tech UI</span>
</div>
<div class="form-grid">
<div class="field">
<label>账本机构 accounting_orgid</label>
<input id="accountingOrgid" placeholder="请输入账本机构ID" />
</div>
<div class="two">
<div class="field">
<label>对手方类型</label>
<select id="counterpartyType">
<option value="supplier">供应商 supplier</option>
<option value="reseller">分销商 reseller</option>
</select>
</div>
<div class="field">
<label>账期类型</label>
<select id="periodType">
<option value="day">日结 day</option>
<option value="month">月结 month</option>
</select>
</div>
</div>
<div class="field">
<label>对手方机构 counterparty_orgid</label>
<input id="counterpartyOrgid" placeholder="汇总可不填;预览/创建必填" />
</div>
<div class="two">
<div class="field">
<label>开始日期</label>
<input id="startDate" type="date" />
</div>
<div class="field">
<label>结束日期</label>
<input id="endDate" type="date" />
</div>
</div>
<div class="two">
<div class="field">
<label>页码</label>
<input id="currentPage" type="number" min="1" value="1" />
</div>
<div class="field">
<label>每页数量</label>
<input id="pageSize" type="number" min="1" value="20" />
</div>
</div>
<div class="field">
<label>结算单 ID settlement_id</label>
<input id="settlementId" placeholder="提交审批/详情时填写" />
</div>
<div class="field">
<label>用户 ID userid</label>
<input id="userid" placeholder="创建/提交审批时填写" />
</div>
<div class="field">
<label>审批 ID apv_id / approval_id</label>
<input id="approvalId" placeholder="审批回调时填写" />
</div>
<div class="field">
<label>审批状态</label>
<select id="approvalStatus">
<option value="agree">agree 审批通过</option>
<option value="start">start 审批中</option>
<option value="refuse">refuse 拒绝</option>
<option value="terminate">terminate 撤销</option>
</select>
</div>
<div class="actions">
<button onclick="querySummary()">汇总查询</button>
<button class="secondary" onclick="previewSettlement()">预览明细</button>
<button class="green" onclick="createSettlement()">创建结算单</button>
<button class="orange" onclick="submitSettlement()">提交审批</button>
<button class="secondary" onclick="queryList()">结算单列表</button>
<button class="secondary" onclick="queryDetail()">结算单详情</button>
<button onclick="approvalCallback()">审批回调</button>
<button class="secondary" onclick="clearResult()">清空结果</button>
</div>
<div class="hint">
推荐流程:汇总查询 -> 预览明细 -> 创建结算单 -> 提交审批 -> 审批回调。接口路径默认按 `/bill/*.dspy` 调用。
</div>
</div>
</aside>
<section class="panel">
<div class="panel-title">
<h2>结算数据</h2>
<span class="badge" id="resultBadge">等待查询</span>
</div>
<div class="tabs">
<button class="tab active" onclick="switchView('table')">数据表格</button>
<button class="tab" onclick="switchView('raw')">接口返回</button>
</div>
<div id="tableView" class="table-wrap">
<table>
<thead id="tableHead">
<tr>
<th>提示</th>
</tr>
</thead>
<tbody id="tableBody">
<tr>
<td>请先执行查询</td>
</tr>
</tbody>
</table>
</div>
<pre id="rawView" class="log" style="display: none;">暂无数据</pre>
</section>
</section>
</main>
<script>
const API = {
summary: "/bill/finance_settlement_summary.dspy",
preview: "/bill/finance_settlement_preview.dspy",
create: "/bill/finance_settlement_create.dspy",
list: "/bill/finance_settlement_list.dspy",
detail: "/bill/finance_settlement_detail.dspy",
submit: "/bill/finance_settlement_submit.dspy",
callback: "/bill/finance_settlement_apv_callback.dspy"
};
const moneyFields = ["sales_amount", "settlement_amount", "platform_income_amount"];
let lastResponse = null;
function $(id) {
return document.getElementById(id);
}
function value(id) {
return $(id).value.trim();
}
function basePayload() {
return {
accounting_orgid: value("accountingOrgid"),
counterparty_type: value("counterpartyType"),
period_type: value("periodType"),
start_date: value("startDate"),
end_date: value("endDate"),
period_start: value("startDate"),
period_end: value("endDate"),
counterparty_orgid: value("counterpartyOrgid"),
current_page: Number(value("currentPage") || 1),
page_size: Number(value("pageSize") || 20)
};
}
function compact(obj) {
return Object.fromEntries(
Object.entries(obj).filter(([, v]) => v !== "" && v !== null && v !== undefined)
);
}
async function postJson(url, payload) {
$("apiStatus").textContent = "Loading";
$("resultBadge").textContent = "请求中";
const response = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(compact(payload))
});
const text = await response.text();
try {
return JSON.parse(text);
} catch (error) {
return { status: false, msg: "接口未返回 JSON", raw: text };
}
}
function setModeText() {
const typeText = value("counterpartyType") === "supplier" ? "供应商" : "分销商";
const periodText = value("periodType") === "day" ? "日结" : "月结";
$("modeText").textContent = `${typeText} / ${periodText}`;
}
function updateMetrics(data) {
const summary = data?.summary || data?.data?.summary || {};
$("salesAmount").textContent = formatMoney(summary.sales_amount);
$("settlementAmount").textContent = formatMoney(summary.settlement_amount);
$("platformIncomeAmount").textContent = formatMoney(summary.platform_income_amount);
$("billCount").textContent = summary.bill_count ?? 0;
}
function formatMoney(value) {
const number = Number(value || 0);
return Number.isFinite(number) ? number.toFixed(8) : "0.00000000";
}
function normalizeRows(resp) {
const data = resp?.data || {};
if (Array.isArray(data.items)) return data.items;
if (Array.isArray(data)) return data;
if (data.settlement) return [data.settlement, ...(data.items || [])];
return [];
}
function render(resp) {
lastResponse = resp;
$("rawView").textContent = JSON.stringify(resp, null, 2);
$("apiStatus").textContent = resp?.status ? "Success" : "Failed";
$("resultBadge").textContent = resp?.status ? "请求成功" : "请求失败";
updateMetrics(resp?.data || {});
const rows = normalizeRows(resp);
if (!rows.length) {
$("tableHead").innerHTML = "<tr><th>提示</th></tr>";
$("tableBody").innerHTML = `<tr><td>${escapeHtml(resp?.msg || "暂无数据")}</td></tr>`;
return;
}
const columns = Array.from(
rows.reduce((set, row) => {
Object.keys(flatten(row)).forEach(key => set.add(key));
return set;
}, new Set())
).slice(0, 14);
$("tableHead").innerHTML = `<tr>${columns.map(col => `<th>${escapeHtml(col)}</th>`).join("")}</tr>`;
$("tableBody").innerHTML = rows.map(row => {
const flat = flatten(row);
return `<tr>${columns.map(col => `<td>${formatCell(col, flat[col])}</td>`).join("")}</tr>`;
}).join("");
}
function flatten(obj, prefix = "", output = {}) {
Object.entries(obj || {}).forEach(([key, val]) => {
const path = prefix ? `${prefix}.${key}` : key;
if (val && typeof val === "object" && !Array.isArray(val)) {
flatten(val, path, output);
} else {
output[path] = Array.isArray(val) ? JSON.stringify(val) : val;
}
});
return output;
}
function formatCell(key, val) {
if (moneyFields.some(field => key.endsWith(field))) {
return `<strong>${formatMoney(val)}</strong>`;
}
if (key.endsWith("status") && val) {
return `<span class="tag">${escapeHtml(val)}</span>`;
}
return escapeHtml(val ?? "");
}
function escapeHtml(value) {
return String(value)
.replaceAll("&", "&amp;")
.replaceAll("<", "&lt;")
.replaceAll(">", "&gt;")
.replaceAll('"', "&quot;")
.replaceAll("'", "&#039;");
}
function requireFields(payload, fields) {
const missing = fields.filter(field => !payload[field]);
if (missing.length) {
const resp = { status: false, msg: `缺少参数: ${missing.join(", ")}` };
render(resp);
return false;
}
return true;
}
async function querySummary() {
setModeText();
const payload = basePayload();
if (!requireFields(payload, ["accounting_orgid", "counterparty_type", "period_type", "start_date", "end_date"])) return;
render(await postJson(API.summary, payload));
}
async function previewSettlement() {
setModeText();
const payload = basePayload();
if (!requireFields(payload, ["accounting_orgid", "counterparty_type", "counterparty_orgid", "period_start", "period_end"])) return;
render(await postJson(API.preview, payload));
}
async function createSettlement() {
setModeText();
const payload = { ...basePayload(), userid: value("userid") };
if (!requireFields(payload, ["accounting_orgid", "counterparty_type", "counterparty_orgid", "period_start", "period_end"])) return;
render(await postJson(API.create, payload));
}
async function queryList() {
setModeText();
const payload = basePayload();
if (!requireFields(payload, ["accounting_orgid"])) return;
render(await postJson(API.list, payload));
}
async function queryDetail() {
const payload = {
settlement_id: value("settlementId"),
current_page: Number(value("currentPage") || 1),
page_size: Number(value("pageSize") || 100)
};
if (!requireFields(payload, ["settlement_id"])) return;
render(await postJson(API.detail, payload));
}
async function submitSettlement() {
const payload = {
settlement_id: value("settlementId"),
userid: value("userid"),
business_name: "财务结算"
};
if (!requireFields(payload, ["settlement_id", "userid"])) return;
render(await postJson(API.submit, payload));
}
async function approvalCallback() {
const payload = {
apv_id: value("approvalId"),
status: value("approvalStatus")
};
if (!requireFields(payload, ["apv_id", "status"])) return;
render(await postJson(API.callback, payload));
}
function switchView(view) {
document.querySelectorAll(".tab").forEach(tab => tab.classList.remove("active"));
event.target.classList.add("active");
$("tableView").style.display = view === "table" ? "block" : "none";
$("rawView").style.display = view === "raw" ? "block" : "none";
}
function clearResult() {
lastResponse = null;
$("rawView").textContent = "暂无数据";
$("tableHead").innerHTML = "<tr><th>提示</th></tr>";
$("tableBody").innerHTML = "<tr><td>请先执行查询</td></tr>";
$("apiStatus").textContent = "Ready";
$("resultBadge").textContent = "等待查询";
updateMetrics({});
}
setModeText();
$("counterpartyType").addEventListener("change", setModeText);
$("periodType").addEventListener("change", setModeText);
</script>
</body>
</html>

View File

@ -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",

View File

@ -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(/&nbsp;/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]*)</g
let updated = template.replace(textNodeRegex, (full, inner) => {
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(/<template>([\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 = `<template>${updated}</template>`
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`)

View File

@ -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
})
}

View File

@ -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){

View File

@ -54,6 +54,24 @@
<div class="content unicode" style="display: block;">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont">&#xe624;</span>
<div class="name">右箭头</div>
<div class="code-name">&amp;#xe624;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe63c;</span>
<div class="name"></div>
<div class="code-name">&amp;#xe63c;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe63d;</span>
<div class="name"></div>
<div class="code-name">&amp;#xe63d;</div>
</li>
<li class="dib">
<span class="icon iconfont">&#xe600;</span>
<div class="name">购物车空</div>
@ -156,9 +174,9 @@
<pre><code class="language-css"
>@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');
}
</code></pre>
<h3 id="-iconfont-">第二步:定义使用 iconfont 的样式</h3>
@ -184,6 +202,33 @@
<div class="content font-class">
<ul class="icon_lists dib-box">
<li class="dib">
<span class="icon iconfont icon-youjiantou"></span>
<div class="name">
右箭头
</div>
<div class="code-name">.icon-youjiantou
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-shang"></span>
<div class="name">
</div>
<div class="code-name">.icon-shang
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-xia"></span>
<div class="name">
</div>
<div class="code-name">.icon-xia
</div>
</li>
<li class="dib">
<span class="icon iconfont icon-gouwuchekong"></span>
<div class="name">
@ -337,6 +382,30 @@
<div class="content symbol">
<ul class="icon_lists dib-box">
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-youjiantou"></use>
</svg>
<div class="name">右箭头</div>
<div class="code-name">#icon-youjiantou</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-shang"></use>
</svg>
<div class="name"></div>
<div class="code-name">#icon-shang</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-xia"></use>
</svg>
<div class="name"></div>
<div class="code-name">#icon-xia</div>
</li>
<li class="dib">
<svg class="icon svg-icon" aria-hidden="true">
<use xlink:href="#icon-gouwuchekong"></use>

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 5043107 */
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 {
@ -13,6 +13,18 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-youjiantou:before {
content: "\e624";
}
.icon-shang:before {
content: "\e63c";
}
.icon-xia:before {
content: "\e63d";
}
.icon-gouwuchekong:before {
content: "\e600";
}

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,27 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "1304892",
"name": "右箭头",
"font_class": "youjiantou",
"unicode": "e624",
"unicode_decimal": 58916
},
{
"icon_id": "1305406",
"name": "上",
"font_class": "shang",
"unicode": "e63c",
"unicode_decimal": 58940
},
{
"icon_id": "1305407",
"name": "下",
"font_class": "xia",
"unicode": "e63d",
"unicode_decimal": 58941
},
{
"icon_id": "1306",
"name": "购物车空",

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

View File

@ -0,0 +1,517 @@
.news-view-page {
position: relative;
min-height: 100vh;
overflow-x: hidden;
color: #1f2937;
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%),
linear-gradient(180deg, #f2f8ff 0%, #f6fbff 36%, #fbfdff 62%, #f5f8ff 100%);
}
.news-shell {
position: relative;
z-index: 1;
max-width: 1280px;
margin: 0 auto;
padding: 0 24px;
}
.orb {
position: fixed;
z-index: 0;
border-radius: 50%;
filter: blur(110px);
opacity: 0.18;
pointer-events: none;
}
.orb-1 {
top: -100px;
left: -100px;
width: 400px;
height: 400px;
background: #3b82f6;
animation: float1 20s ease-in-out infinite;
}
.orb-2 {
right: -150px;
bottom: -150px;
width: 500px;
height: 500px;
background: #3b82f6;
animation: float2 25s ease-in-out infinite;
}
.orb-3 {
top: 50%;
left: 50%;
width: 300px;
height: 300px;
background: #ec4899;
opacity: 0.12;
animation: float3 18s ease-in-out infinite;
}
.news-hero {
position: relative;
padding: 140px 0 72px;
overflow: hidden;
}
.news-hero::before {
position: absolute;
inset: 0;
z-index: 0;
content: '';
// background:
// linear-gradient(135deg, rgba(99,102,241,0.055) 0%, rgba(168,85,247,0.04) 50%, rgba(236,72,153,0.025) 100%),
// linear-gradient(180deg, rgba(255,255,255,0) 0%, rgba(255,255,255,0.62) 100%);
}
.news-hero-glow {
position: absolute;
z-index: 0;
border-radius: 50%;
}
.news-hero-glow-1 {
top: -60px;
right: -100px;
width: 500px;
height: 500px;
background: radial-gradient(circle, rgba(139,92,246,0.09) 0%, transparent 72%);
}
.news-hero-glow-2 {
bottom: -80px;
left: -120px;
width: 600px;
height: 600px;
background: radial-gradient(circle, rgba(59,130,246,0.08) 0%, transparent 72%);
}
.hero-content {
animation: fadeInUp 0.8s ease-out forwards;
}
.hero-badge {
display: inline-block;
padding: 6px 16px;
margin-bottom: 24px;
color: #6366f1;
font-size: 13px;
font-weight: 600;
background: rgba(99, 102, 241, 0.1);
border-radius: 50px;
}
.hero-title-row {
display: flex;
gap: 20px;
align-items: baseline;
margin-bottom: 14px;
}
.hero-title-row h1 {
margin: 0;
color: #1a1a1a;
font-size: 56px;
font-weight: 700;
line-height: 1.2;
}
.about-link {
padding: 0;
color: #6b7280;
font-size: 16px;
white-space: nowrap;
cursor: pointer;
background: transparent;
border: 0;
transition: color 0.2s;
}
.about-link:hover {
color: #2563eb;
}
.hero-content p {
max-width: 600px;
margin: 0;
color: #6b7280;
font-size: 18px;
line-height: 1.8;
}
.filter-section {
padding: 8px 0 34px;
}
.filter-tabs {
display: inline-flex;
flex-wrap: wrap;
gap: 10px;
align-items: center;
padding: 8px;
background: rgba(255, 255, 255, 0.78);
border: 1px solid rgba(226, 232, 240, 0.82);
border-radius: 999px;
box-shadow: 0 12px 34px rgba(31, 45, 61, 0.06);
backdrop-filter: blur(14px);
}
.filter-tab {
min-width: 86px;
min-height: 40px;
padding: 10px 24px;
color: #6b7280;
font-size: 15px;
font-weight: 600;
cursor: pointer;
background: transparent;
border: 1px solid transparent;
border-radius: 50px;
transition: all 0.3s ease;
}
.filter-tab:hover {
color: #1a1a1a;
background: #f3f4f6;
}
.filter-tab.active {
color: #fff;
background: #1a1a1a;
border-color: #1a1a1a;
box-shadow: 0 8px 18px rgba(17, 24, 39, 0.16);
}
.featured-section {
padding-bottom: 52px;
}
.news-featured,
.news-item {
position: relative;
overflow: hidden;
cursor: pointer;
background: #fff;
border: 1px solid rgba(0, 0, 0, 0.04);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.news-featured {
border-radius: 24px;
}
.hover-detail {
position: absolute;
top: 18px;
right: 18px;
z-index: 5;
display: inline-flex;
gap: 4px;
align-items: center;
height: 32px;
padding: 0 14px;
color: #fff;
font-size: 13px;
font-weight: 600;
line-height: 32px;
pointer-events: none;
background: rgba(17, 24, 39, 0.72);
border: 1px solid rgba(255, 255, 255, 0.22);
border-radius: 999px;
opacity: 0;
transform: translateY(-6px);
transition: all 0.24s ease;
backdrop-filter: blur(10px);
}
.news-featured:hover .hover-detail,
.news-item:hover .hover-detail {
opacity: 1;
transform: translateY(0);
}
.news-featured:hover,
.news-item:hover {
border-color: rgba(99, 102, 241, 0.15);
box-shadow: 0 20px 60px rgba(99, 102, 241, 0.12), 0 8px 24px rgba(0, 0, 0, 0.06);
}
.news-featured:hover {
transform: translateY(-4px);
}
.news-item:hover {
transform: translateY(-6px);
}
.news-featured-inner {
display: grid;
grid-template-columns: 1fr 2fr;
min-height: 180px;
}
.news-featured-img,
.news-item-img {
position: relative;
overflow: hidden;
}
.news-featured-img img,
.news-item-img img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.6s cubic-bezier(0.4, 0, 0.2, 1);
}
.news-featured:hover img,
.news-item:hover img {
transform: scale(1.04);
}
.news-featured-body {
display: flex;
flex-direction: column;
justify-content: center;
padding: 24px 40px;
}
.news-featured-date {
margin-bottom: 16px;
color: #9ca3af;
font-size: 14px;
}
.category-pill {
display: inline-block;
padding: 4px 12px;
margin-right: 8px;
color: #fff;
font-size: 12px;
font-weight: 600;
border-radius: 20px;
}
.news-featured h2 {
margin: 0 0 16px;
color: #1a1a1a;
font-size: 22px;
font-weight: 700;
line-height: 1.4;
transition: color 0.3s;
}
.news-featured p {
margin: 0 0 24px;
color: #6b7280;
font-size: 15px;
line-height: 1.8;
}
.news-featured:hover h2,
.news-item:hover h3 {
color: #4f46e5;
}
.news-list-section {
padding-bottom: 60px;
}
.news-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 32px;
}
.news-item {
border-radius: 20px;
animation: fadeInUp 0.8s ease-out forwards;
}
.news-item-img {
width: 100%;
height: 220px;
}
.news-item-img-overlay {
position: absolute;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
height: 60%;
background: linear-gradient(to top, rgba(0, 0, 0, 0.4), transparent);
}
.news-item-tag {
position: absolute;
top: 16px;
left: 16px;
z-index: 2;
padding: 4px 12px;
color: #fff;
font-size: 12px;
font-weight: 600;
border-radius: 20px;
backdrop-filter: blur(8px);
}
.news-item-body {
padding: 24px;
}
.news-item-date {
margin-bottom: 10px;
color: #9ca3af;
font-size: 13px;
}
.news-item h3 {
display: -webkit-box;
margin: 0 0 10px;
overflow: hidden;
color: #1a1a1a;
font-size: 18px;
font-weight: 700;
line-height: 1.5;
line-clamp: 2;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
transition: color 0.3s;
}
.news-item p {
display: -webkit-box;
margin: 0;
overflow: hidden;
color: #6b7280;
font-size: 14px;
line-height: 1.7;
line-clamp: 3;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
.news-item-glow {
position: absolute;
top: 0;
left: 0;
z-index: 0;
width: 100%;
height: 100%;
pointer-events: none;
background: radial-gradient(circle at 50% 50%, rgba(139, 92, 246, 0.1) 0%, rgba(59, 130, 246, 0.06) 30%, transparent 70%);
opacity: 0;
transition: opacity 0.5s ease;
}
.news-item:hover .news-item-glow,
.news-featured:hover .news-item-glow {
opacity: 1;
}
.pagination {
display: flex;
gap: 8px;
align-items: center;
justify-content: center;
margin-top: 48px;
}
.pagination-btn {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
color: #6b7280;
font-size: 14px;
font-weight: 500;
cursor: pointer;
background: #fff;
border: 1px solid #e5e7eb;
border-radius: 10px;
transition: all 0.2s ease;
}
.pagination-btn:hover {
color: #6366f1;
border-color: #6366f1;
}
.pagination-btn.active {
color: #fff;
background: #1a1a1a;
border-color: #1a1a1a;
}
@keyframes float1 {
0%, 100% { transform: translate(0, 0) scale(1); }
33% { transform: translate(50px, -50px) scale(1.1); }
66% { transform: translate(-30px, 30px) scale(0.9); }
}
@keyframes float2 {
0%, 100% { transform: translate(0, 0) scale(1); }
33% { transform: translate(-60px, 40px) scale(1.15); }
66% { transform: translate(40px, -60px) scale(0.85); }
}
@keyframes float3 {
0%, 100% { transform: translate(-50%, -50%) scale(1); }
50% { transform: translate(-30%, -70%) scale(1.2); }
}
@keyframes fadeInUp {
from { opacity: 0; transform: translateY(30px); }
to { opacity: 1; transform: translateY(0); }
}
@media (max-width: 1024px) {
.news-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 768px) {
.news-hero {
padding: 120px 0 56px;
}
.hero-title-row {
flex-direction: column;
gap: 10px;
align-items: flex-start;
}
.filter-tabs {
display: flex;
border-radius: 20px;
}
.filter-tab {
min-width: auto;
padding: 8px 16px;
font-size: 14px;
}
.news-featured-inner,
.news-grid {
grid-template-columns: 1fr;
}
.news-featured-img {
height: 220px;
}
.news-featured-body {
padding: 24px;
}
}

View File

@ -1,158 +1,21 @@
<template>
<div class="box">
<div>
<div class="contener" v-if=" orgType == 2 || orgType == 3 || !userid">
<div class="contener" v-if="shouldShowFloatingConsult">
<transition name="slide">
<div v-show="windowsHidden" style="font-size: 14px">
<div class="new-floating" style="z-index: 99;">
<img src="./img/head.png" alt="">
<div class="cloud-contact-us " @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave">
<!-- <span class="cloud-contact-us-i"></span>-->
<span> </span>
<span> </span>
<span> </span>
<span> </span>
</div>
<!-- <div class="cart-entry-wrapper" @click="tryUse">-->
<!-- <el-tooltip class="item" effect="light" content="申请试用" placement="left">-->
<!-- <div class="cart-entry">-->
<!-- <span class="cart-icon"></span>-->
<!-- </div>-->
<!-- </el-tooltip>-->
<!-- </div>-->
<div @click="open2"
style="position:absolute;bottom:-40px;display: flex;justify-content: center;align-items: center;cursor: pointer">
<!-- 摄像头 -->
<!-- <el-tooltip v-if="getHomePath()!=='/ncmatchHome/index'" class="item" effect="light" content="联系销售" placement="left">
<span class="el-icon-video-camera"
style="font-weight: 550;font-size: 22px;"></span>
</el-tooltip> -->
<!-- </div>-->
<!-- <div class="cart-entry-wrapper" style="visibility: visible;">-->
<!-- <div class="cart-entry" data-track-category="购物车浮层" data-track-name="入口点击"-->
<!-- data-track-action="click"><span class="cart-icon"></span></div>-->
<!-- <span class="cart-icon"></span>-->
</div>
</div>
<!-- <div class="floating-box" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave"-->
<!-- style="cursor: default;">-->
<!-- <span>联系我们</span>-->
<!-- </div>-->
<!-- <div class="floating-box1" @click="tryUse">-->
<!-- <span>申请试用</span>-->
<!-- </div>-->
</div>
</transition>
<!-- <transition name="slide">-->
<!-- <div v-show="windowsHidden">-->
<!-- <div class="floating-box" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave"-->
<!-- style="cursor: default;">-->
<!-- <i class="el-icon-s-comment"></i>-->
<!-- <span>联系我们</span>-->
<!-- </div>-->
<!-- <div class="floating-box1" @click="tryUse">-->
<!-- <i class="el-icon-s-order"></i>-->
<!-- <span>申请试用</span>-->
<!-- </div>-->
<!-- </div>-->
<!-- </transition>-->
<div v-if="false" @click="windowsHidden=!windowsHidden" class="floating-box1 hiddenBtn"
style="width: 50px;height: 50px;border-radius:50%;bottom: 30px;background-color: #f1e9e9;color: blue">
<i class="el-icon-arrow-right" style="color: blue" v-show="windowsHidden"></i>
<i class="el-icon-arrow-left" style="color: blue" v-show="!windowsHidden"></i>
</div>
<transition name="el-zoom-in-top">
<!--isShow&&windowsHidden -->
<div v-show="isShow&&windowsHidden" class="cloud-contact-us-spread-container" style="z-index: 9">
<ul class="cloud-contact-us-spread" style="padding-left: 15px;">
<li class="cloud-contact-us-tel" style="height: 90px;">
<div style="display: flex;justify-content: center;align-items: center;padding-top: 15px">
<div data-track-action="click" data-track-category="右侧公共悬浮区" data-track-name="售前咨询"
data-agl-cvt="5"
style="height: 100%;display: flex;justify-content: center;align-items: center;flex-direction: column;">
<div
style="margin-left: -50px;width: 100px;height: 30px;display: flex;justify-content: center;align-items: center">
<span style="margin-right: 5px;margin-top: 17px;height: 35px;"
class="cloud-contact-us-icon"></span>
<p class="cloud-contact-us-tit" style="font-size: 14px;">售前咨询</p>
</div>
<div style="display: flex;justify-content: center;align-items: center;"
>
<div v-if="!phone"
style="width: 80px;height: 25px;display: flex!important;justify-content: center;align-items: center">
<el-skeleton
style="width: 100%;padding: 0;margin: 0;height: 100%;margin-top: -25px"
:rows="1"
animated/>
</div>
<p v-else class="cloud-contact-us-con" style="font-size: 12px;height: 20px;margin-top: 5px">
{{ phone }}</p></div>
</div>
<div v-if="false" style="width: 90px;height: 90px;">
<div class="img"
style="width: 90px;height: 90px; display: flex;justify-content: center;align-items: center"
>
<el-skeleton style="width: 80px;height: 80px;" :loading="loading" animated
v-if="isShowPicLoading">
<template slot="template">
<el-skeleton-item
variant="image"
style="width: 80px; height:80px ;"
/>
</template>
</el-skeleton>
<img style="width: 80px;height: 80px;" v-else @load="onImageLoad" :src="src" alt="">
</div>
</div>
<div class="floating-consult">
<a href="#" class="floating-consult-btn primary" @click.prevent="openAiConsult">
<div class="floating-consult-icon">
<img src="./img/ocai.jpg" alt="在线咨询">
<span class="consult-badge"></span>
</div>
</li>
</ul>
<!-- <span class="floating-consult-text">在线咨询</span> -->
</a>
</div>
</div>
<!-- <div class="dialog" v-if="false"-->
<!-- style="display: flex;justify-content: space-around;">-->
<!-- <div class="phone">-->
<!-- <span class="sonOne">业务咨询</span>-->
<!-- <span class="sonTwo">生态合作总监</span>-->
<!-- <span class="sonThree" style="display: flex;">-->
<!-- 电话:-->
<!-- <el-skeleton style="width: 120px" animated v-if="isShowPicLoading">-->
<!-- <template slot="template">-->
<!-- <el-skeleton-item variant="image" style="width: 70px; height: 20px;"/>-->
<!-- </template>-->
<!-- </el-skeleton>-->
<!-- <span v-else>{{ phone }}</span>-->
<!-- </span>-->
<!-- </div>-->
<!-- <div class="img" style="display: flex;justify-content: center;align-items: center"-->
<!-- >-->
<!-- <el-skeleton style="width: 100%" :loading="loading" animated v-if="isShowPicLoading">-->
<!-- <template slot="template">-->
<!-- <el-skeleton-item-->
<!-- variant="image"-->
<!-- style="width: 100px; height:100px ;"-->
<!-- />-->
<!-- </template>-->
<!-- </el-skeleton>-->
<!-- <img v-else @load="onImageLoad" :src="src" alt="">-->
<!-- </div>-->
<!-- </div>-->
</transition>
@ -216,6 +79,7 @@ import axios from "axios";
import {mapState} from "vuex";
import {getCustomerOfSaleUserId} from "@/api/customer/vedio";
import { getHomePath } from "@/views/setting/tools";
import { reqNewHomeConsult } from "@/api/newHome";
export default {
//
@ -286,7 +150,16 @@ export default {
// console.log("~~~",this.$route)
},
computed: {},
computed: {
shouldShowFloatingConsult() {
const isHomePage = [
'/homePage/index',
'/homePage/indexLast',
'/ncmatchHome/index'
].includes(this.$route.path)
return isHomePage || this.orgType == 2 || this.orgType == 3 || !this.userid
}
},
methods: {
// getHomePath()
getHomePath,
@ -381,6 +254,378 @@ export default {
open2() {
this.isShowChangeChat = true
},
openAiConsult() {
this.resetYunbaoChatInstance()
this.installYunbaoChat()
window.YunbaoChat.init({
avatarUrl: require('./img/ocai.jpg'),
name: '云宝小助手'
})
window.YunbaoChat.open()
},
resetYunbaoChatInstance() {
const oldModal = document.getElementById('yunbaoModal')
const oldStyle = document.getElementById('yunbao-chat-css')
if (oldModal) oldModal.remove()
if (oldStyle) oldStyle.remove()
window.YunbaoChat = null
},
installYunbaoChat() {
if (window.YunbaoChat && document.getElementById('yunbaoModal')) return
if (window.YunbaoChat && !document.getElementById('yunbaoModal')) {
window.YunbaoChat = null
}
const vm = this
window.YunbaoChat = {
_inited: false,
_chatInited: false,
_selectedProduct: '',
_config: {},
init(config = {}) {
if (this._inited) return
this._inited = true
this._config = Object.assign({
avatarUrl: '',
name: '云宝小助手',
submitUrl: '',
products: [
{ key: 'E投标', intro: 'E投标智能体是覆盖「招标解析→标书编制→合规审查→查重→知识沉淀」全链路的一站式投标AI解决方案帮企业将编标周期从数天压缩至小时级低级废标率降低100%。' },
{ key: 'E招标', intro: 'E招标智能体AI辅助编制招标文件自动合规性审查让招标流程更高效、更透明、更合规。' },
{ key: 'E评标', intro: 'E评标智能体AI辅助评标分析自动提取关键指标、横向对比评分、识别异常报价帮助评标专家高效、公正地完成评审工作。' },
{ key: '采伐智审', intro: '面向林业管理的行业智能体,可在线完成采伐申请材料的智能核验,自动比对采伐范围、树种、蓄积量等核心指标与合规要求,快速识别违规申请,助力林业资源可持续利用。' },
{ key: '燃机智慧监盘', intro: '能源领域工业智能体实时采集燃机运行的温度、压力、振动等多维度数据通过AI算法识别异常运行征兆提前预判潜在故障保障燃机稳定运行降低运维成本。' },
{ key: '电价预测', intro: '面向能源行业的预测智能体,结合历史电价数据、供需变化、政策调整、天气影响等多维度变量,通过机器学习模型实现不同周期的电价精准预测,帮助电力企业优化收益管理。' },
{ key: 'AI漫剧制作', intro: '互联网内容创作智能体覆盖从剧本生成、分镜拆解、素材生成到视频合成的全流程制作。支持工业化批量生产帮助中小团队低成本快速产出AI漫画作品大幅降低创作门槛。' },
{ key: '合同智能审查', intro: 'AI驱动的办公智能体可快速识别合同中的风险条款、表述歧义、合规漏洞自动标注问题位置并给出修改建议。支持多类型合同模板适配大幅缩短人工审查时长。' },
{ key: '投策智能体', intro: '面向企业投资决策的辅助智能体,整合多维度市场数据、行业趋势与政策信息,通过算法模拟不同决策场景的收益与风险,自动生成可视化分析报告,提升投资方案科学性。' }
],
pages: {
'合同智能审查': '/homePage/agentStore/contractCase',
'投策智能体': '/homePage/agentStore/decisionCase'
}
}, config)
this.injectCSS()
this.injectHTML()
this.bindBaseEvents()
},
open() {
const modal = document.getElementById('yunbaoModal')
if (!modal) return
modal.querySelectorAll('.yb-chat-avatar img,.yb-chat-msg-avatar img').forEach((img) => {
img.src = this._config.avatarUrl
})
modal.classList.add('active')
if (!this._chatInited) {
this._chatInited = true
this.initChat()
}
},
close() {
const modal = document.getElementById('yunbaoModal')
if (modal) modal.classList.remove('active')
},
injectCSS() {
if (document.getElementById('yunbao-chat-css')) return
const style = document.createElement('style')
style.id = 'yunbao-chat-css'
style.textContent = vm.getYunbaoChatCSS()
document.head.appendChild(style)
},
injectHTML() {
if (document.getElementById('yunbaoModal')) return
const div = document.createElement('div')
div.innerHTML = vm.getYunbaoChatHTML(this._config)
document.body.appendChild(div.firstElementChild)
},
bindBaseEvents() {
const modal = document.getElementById('yunbaoModal')
const closeBtn = document.getElementById('yunbaoCloseBtn')
if (modal) {
modal.addEventListener('click', (event) => {
if (event.target === modal) this.close()
})
}
if (closeBtn) closeBtn.addEventListener('click', () => this.close())
},
initChat() {
const body = document.getElementById('yunbaoChatBody')
if (!body) return
body.innerHTML = ''
setTimeout(() => {
this.addBotMsg('嗨~我是云宝 👋<br>请问您想随便看看,还是直接聊聊需求?', [
{ text: '随便看看', action: 'browse' },
{ text: '直接聊聊需求', action: 'direct' }
])
}, 200)
},
addBotMsg(html, options = [], displayType = '') {
const body = document.getElementById('yunbaoChatBody')
if (!body) return
const msg = document.createElement('div')
msg.className = 'yb-chat-msg'
const type = displayType || (options[0] && options[0].type) || ''
let optionHtml = ''
if (options.length) {
if (type === 'cards') {
optionHtml = `<div class="yb-chat-product-cards">${options.map(item => `
<div class="yb-chat-product-card" data-action="${item.action || ''}" data-param="${item.param || ''}" data-url="${item.url || ''}" data-text="${item.text || ''}">
<div class="yb-chat-product-card-title">${item.text}</div>
<div class="yb-chat-product-card-desc">${item.desc || ''}</div>
<span class="yb-chat-product-card-link">查看更多 </span>
</div>
`).join('')}</div>`
} else if (type === 'tags') {
optionHtml = `<div class="yb-chat-tag-options">${options.map(item => `<button class="yb-chat-tag-btn" data-action="${item.action || ''}" data-param="${item.param || ''}" data-text="${item.text || ''}">${item.text}</button>`).join('')}</div>`
} else {
optionHtml = `<div class="yb-chat-options">${options.map(item => `<button class="${item.primary ? 'yb-chat-option-btn primary' : 'yb-chat-option-btn'}" data-action="${item.action || ''}" data-param="${item.param || ''}" data-text="${item.text || ''}">${item.text}</button>`).join('')}</div>`
}
}
msg.innerHTML = `
<div class="yb-chat-msg-avatar"><img src="${this._config.avatarUrl}" alt="云宝"></div>
<div>
<div class="yb-chat-msg-bubble">${html}</div>
${optionHtml}
</div>
`
body.appendChild(msg)
body.scrollTop = body.scrollHeight
msg.querySelectorAll('[data-action]').forEach(btn => {
btn.addEventListener('click', () => this.handleAction(btn.getAttribute('data-action'), btn.getAttribute('data-param'), btn.getAttribute('data-text') || btn.innerText.trim(), btn.getAttribute('data-url')))
})
},
addUserMsg(text) {
const body = document.getElementById('yunbaoChatBody')
if (!body) return
const msg = document.createElement('div')
msg.className = 'yb-chat-msg yb-chat-msg-user'
msg.innerHTML = `<div class="yb-chat-msg-avatar yb-chat-user-avatar"><span>👤</span></div><div class="yb-chat-msg-bubble">${text}</div>`
body.appendChild(msg)
body.scrollTop = body.scrollHeight
},
handleAction(action, param, text, url) {
this.addUserMsg(text || param)
if (action === 'retrySubmit') {
setTimeout(() => this.submitForm(), 200)
return
}
if (action === 'browse') {
setTimeout(() => {
this.addBotMsg('好的~为您推荐我们的热门产品 👇', [
{ text: 'E投标', desc: '更智能的标书写作引擎', action: 'goExternal', url: 'https://bid-ocai-v2.jinan.opencomputing.cn/', type: 'cards' },
{ text: '合同智能审查', desc: 'AI驱动合同风险审查效率提升60%+', action: 'goContract', type: 'cards' },
{ text: '投策智能体', desc: '分钟级投研分析,精准辅助投资决策', action: 'goInvest', type: 'cards' }
])
setTimeout(() => {
this.addBotMsg('或者您还有其他想了解的产品吗?', this.getProductTags(), 'tags')
}, 1200)
}, 200)
return
}
if (action === 'direct') {
setTimeout(() => {
this.addBotMsg('您想了解哪方面的产品或服务呢?', this.getProductTags(), 'tags')
}, 200)
return
}
if (action === 'goContract') {
vm.$router.push(this._config.pages['合同智能审查'] || '/homePage/agentStore/contractCase').catch(() => {})
this.close()
setTimeout(() => {
this.addBotMsg('已为您打开合同智能审查页面 📄<br>还有其他想了解的吗?', this.getProductTags(), 'tags')
}, 200)
return
}
if (action === 'goExternal') {
window.open(url, '_blank')
setTimeout(() => {
this.addBotMsg('已为您打开相关页面。还有其他想了解的吗?', this.getProductTags(), 'tags')
}, 200)
return
}
if (action === 'goInvest') {
vm.$router.push(this._config.pages['投策智能体'] || '/homePage/agentStore/decisionCase').catch(() => {})
this.close()
setTimeout(() => {
this.addBotMsg('已为您打开投策智能体页面 📊<br>还有其他想了解的吗?', this.getProductTags(), 'tags')
}, 200)
return
}
if (action === 'productIntro') {
this._selectedProduct = param
const intro = this.getProductIntro(param)
setTimeout(() => {
this.addBotMsg(intro)
setTimeout(() => this.addContactForm(), 800)
}, 200)
return
}
},
getProductTags() {
return this._config.products.map(item => ({
text: item.key,
action: 'productIntro',
param: item.key
}))
},
getProductIntro(key) {
const product = this._config.products.find(item => item.key === key)
return product ? product.intro : '这是一款优秀的AI产品欢迎进一步了解'
},
addContactForm() {
const body = document.getElementById('yunbaoChatBody')
if (!body) return
const form = document.createElement('div')
form.className = 'yb-chat-msg'
form.innerHTML = `
<div class="yb-chat-msg-avatar"><img src="${this._config.avatarUrl}" alt="云宝"></div>
<div>
<div class="yb-chat-msg-bubble">
请留下您的联系方式我们的顾问将尽快与您联系 😊
<div class="yb-chat-form">
<input type="text" class="yb-chat-form-input" id="yunbaoChatName" placeholder="您的姓名">
<input type="tel" class="yb-chat-form-input" id="yunbaoChatPhone" placeholder="联系电话">
<input type="text" class="yb-chat-form-input" id="yunbaoChatCompany" placeholder="公司名称">
<button class="yb-chat-form-submit" id="yunbaoChatSubmit">提交咨询</button>
<div class="yb-chat-form-tip">信息仅用于顾问联系</div>
</div>
</div>
</div>
`
body.appendChild(form)
body.scrollTop = body.scrollHeight
document.getElementById('yunbaoChatSubmit').addEventListener('click', () => this.submitForm())
},
async submitForm() {
const name = document.getElementById('yunbaoChatName').value.trim()
const phone = document.getElementById('yunbaoChatPhone').value.trim()
const company = document.getElementById('yunbaoChatCompany').value.trim()
const submitBtn = document.getElementById('yunbaoChatSubmit')
if (!name || !phone) {
this.addBotMsg('请先填写姓名和联系电话哦~')
return
}
if (!/^1[3-9]\d{9}$/.test(phone)) {
this.addBotMsg('请输入正确的 11 位手机号哦~')
return
}
if (submitBtn && submitBtn.disabled) return
if (submitBtn) {
submitBtn.disabled = true
submitBtn.innerText = '提交中...'
}
this.addUserMsg('已提交联系方式')
const data = {
custom_type: '1',
name,
phone,
company,
email: '',
content: this._selectedProduct ? `我想咨询关于【${this._selectedProduct}】的产品信息` : '云宝对话咨询',
source: '官网',
url_link: window.location.href
}
try {
const response = await reqNewHomeConsult(data)
if (response && response.status) {
this.addBotMsg('收到!我们的顾问将尽快与您联系 🎉<br>感谢您的信任!')
return
}
this.addBotMsg((response && response.msg) || '提交失败了,您可以稍后重试。', [
{ text: '重新提交', action: 'retrySubmit', primary: true }
])
} catch (error) {
this.addBotMsg('网络开小差了,提交失败,您可以重试一次。', [
{ text: '重新提交', action: 'retrySubmit', primary: true }
])
} finally {
if (submitBtn) {
submitBtn.disabled = false
submitBtn.innerText = '提交咨询'
}
}
}
}
},
getYunbaoChatHTML(config) {
return `
<div id="yunbaoModal" class="yb-assistant-modal-overlay">
<div class="yb-assistant-modal">
<div class="yb-assistant-modal-header">
<div class="yb-chat-avatar"><img src="${config.avatarUrl}" alt="云宝"></div>
<div class="yb-chat-header-info">
<div class="yb-chat-header-name">${config.name}</div>
<div class="yb-chat-header-status">在线</div>
</div>
<button class="yb-assistant-close-btn" id="yunbaoCloseBtn">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 6L6 18M6 6l12 12"/></svg>
</button>
</div>
<div class="yb-chat-body" id="yunbaoChatBody"></div>
</div>
</div>
`
},
getYunbaoChatCSS() {
return `
.yb-assistant-modal-overlay{position:fixed;bottom:100px;right:24px;z-index:9999;display:none}
.yb-assistant-modal-overlay.active{display:block}
.yb-assistant-modal{background:rgba(255,255,255,0.85);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border-radius:20px;width:400px;height:560px;display:flex;flex-direction:column;overflow:hidden;box-shadow:0 8px 32px rgba(59,130,246,0.08),0 0 0 1px rgba(255,255,255,0.6) inset;border:1px solid rgba(255,255,255,0.5);animation:ybChatSlideIn 0.35s cubic-bezier(0.34,1.56,0.64,1)}
@keyframes ybChatSlideIn{from{opacity:0;transform:translateY(20px) scale(0.95)}to{opacity:1;transform:translateY(0) scale(1)}}
@keyframes ybToastIn{from{opacity:0;transform:translateX(-50%) translateY(-10px)}to{opacity:1;transform:translateX(-50%) translateY(0)}}
@keyframes ybToastOut{from{opacity:1;transform:translateX(-50%) translateY(0)}to{opacity:0;transform:translateX(-50%) translateY(-10px)}}
.yb-assistant-modal-header{background:linear-gradient(135deg,rgba(240,247,255,0.9) 0%,rgba(255,255,255,0.7) 100%);backdrop-filter:blur(10px);padding:16px 20px;display:flex;align-items:center;gap:12px;flex-shrink:0;border-bottom:1px solid rgba(59,130,246,0.08)}
.yb-chat-avatar{width:48px;height:48px;border-radius:50%;overflow:visible;flex-shrink:0;display:flex;align-items:center;justify-content:center}
.yb-chat-avatar img{width:48px;height:48px;object-fit:contain;display:block}
.yb-chat-header-info{flex:1}
.yb-chat-header-name{font-size:15px;font-weight:600;color:#1e293b}
.yb-chat-header-status{font-size:12px;color:#64748b;display:flex;align-items:center;gap:4px}
.yb-chat-header-status:before{content:"";width:6px;height:6px;border-radius:50%;background:#22c55e;box-shadow:0 0 6px rgba(34,197,94,0.4)}
.yb-assistant-close-btn{width:32px;height:32px;background:rgba(0,0,0,0.04);border-radius:50%;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all 0.2s;border:none}
.yb-assistant-close-btn:hover{background:rgba(0,0,0,0.08)}
.yb-assistant-close-btn svg{width:18px;height:18px;stroke:#64748b}
.yb-chat-body{flex:1;overflow-y:auto;padding:20px;display:flex;flex-direction:column;gap:16px;background:linear-gradient(180deg,rgba(240,247,255,0.3) 0%,rgba(255,255,255,0.1) 100%)}
.yb-chat-body::-webkit-scrollbar{width:4px}
.yb-chat-body::-webkit-scrollbar-thumb{background:rgba(59,130,246,0.15);border-radius:4px}
.yb-chat-msg{display:flex;gap:10px;animation:ybChatMsgIn 0.3s ease}
@keyframes ybChatMsgIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
.yb-chat-msg-avatar{width:40px;height:40px;border-radius:50%;overflow:visible;flex-shrink:0;margin-top:2px;display:flex;align-items:center;justify-content:center}
.yb-chat-msg-avatar img{width:40px;height:40px;object-fit:contain;display:block}
.yb-chat-user-avatar{background:#e2e8f0;font-size:16px;overflow:hidden}
.yb-chat-user-avatar span{display:flex;align-items:center;justify-content:center;width:100%;height:100%}
.yb-chat-msg-bubble{background:#fff;border-radius:16px 16px 16px 4px;padding:12px 16px;font-size:14px;line-height:1.6;color:#334155;max-width:300px;box-shadow:0 1px 3px rgba(0,0,0,0.06)}
.yb-chat-msg-user{flex-direction:row-reverse}
.yb-chat-msg-user .yb-chat-msg-bubble{background:#1e293b;color:#fff;border-radius:16px 16px 4px 16px}
.yb-chat-options{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
.yb-chat-option-btn{padding:8px 16px;border-radius:20px;border:1px solid rgba(59,130,246,0.2);background:rgba(255,255,255,0.8);backdrop-filter:blur(4px);font-size:13px;color:#3b82f6;cursor:pointer;transition:all 0.2s;white-space:nowrap}
.yb-chat-option-btn:hover{border-color:#3b82f6;background:rgba(59,130,246,0.06);box-shadow:0 2px 8px rgba(59,130,246,0.1)}
.yb-chat-option-btn.primary{background:linear-gradient(135deg,#3b82f6,#2563eb);color:#fff;border-color:transparent;box-shadow:0 2px 8px rgba(59,130,246,0.25)}
.yb-chat-product-cards{display:flex;flex-direction:column;gap:10px;margin-top:10px}
.yb-chat-product-card{background:rgba(255,255,255,0.7);border:1px solid rgba(59,130,246,0.1);border-radius:12px;padding:10px 14px!important;height:92px!important;min-height:92px!important;max-height:92px!important;cursor:pointer;transition:all 0.2s;backdrop-filter:blur(4px);box-sizing:border-box;overflow:hidden;display:flex!important;flex-direction:column;justify-content:flex-start}
.yb-chat-product-card:hover{border-color:rgba(59,130,246,0.25);background:rgba(255,255,255,0.9);box-shadow:0 4px 16px rgba(59,130,246,0.08);transform:translateY(-1px)}
.yb-chat-product-card-title{font-size:14px;font-weight:600;color:#1e293b;margin-bottom:4px;line-height:1.3}
.yb-chat-product-card-desc{font-size:12px;color:#64748b;line-height:1.35;margin-bottom:6px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.yb-chat-product-card-link{font-size:12px;color:#3b82f6;font-weight:500;display:inline-flex;align-items:center;gap:4px;line-height:1.2}
.yb-chat-tag-options{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.yb-chat-tag-btn{padding:6px 12px;border-radius:16px;border:1px solid rgba(59,130,246,0.15);background:rgba(255,255,255,0.7);font-size:12px;color:#3b82f6;cursor:pointer;transition:all 0.2s;backdrop-filter:blur(4px)}
.yb-chat-tag-btn:hover{border-color:#3b82f6;background:rgba(59,130,246,0.06);box-shadow:0 2px 8px rgba(59,130,246,0.1)}
.yb-chat-form{margin-top:10px;display:flex;flex-direction:column;gap:10px}
.yb-chat-form-input{width:100%;padding:10px 14px;border:1px solid rgba(59,130,246,0.15);border-radius:10px;font-size:13px;color:#1e293b;background:rgba(255,255,255,0.8);outline:none;transition:all 0.2s;box-sizing:border-box}
.yb-chat-form-input:focus{border-color:#3b82f6;box-shadow:0 0 0 3px rgba(59,130,246,0.08);background:#fff}
.yb-chat-form-input::placeholder{color:#94a3b8}
.yb-chat-form-submit{width:100%;padding:10px;background:#1a1a2e;color:#fff;border:none;border-radius:9999px;font-size:14px;font-weight:500;cursor:pointer;transition:all 0.2s;box-shadow:0 2px 8px rgba(26,26,46,0.2)}
.yb-chat-form-submit:hover{background:#0f0f1a;box-shadow:0 4px 12px rgba(26,26,46,0.3);transform:translateY(-1px)}
.yb-chat-form-submit:disabled{background:#cbd5e1;box-shadow:none;cursor:not-allowed}
.yb-chat-form-tip{font-size:11px;color:#94a3b8;text-align:center}
@media(max-width:480px){.yb-assistant-modal{width:calc(100vw - 32px);height:calc(100vh - 140px);right:0}.yb-assistant-modal-overlay{right:16px;bottom:90px}}
`
},
//
closeWindow() {
this.isShowChangeChat = false
@ -479,6 +724,7 @@ export default {
</script>
<style lang="scss" scoped>
.box {
.contener {
.dialog {
width: 400px;
@ -967,10 +1213,6 @@ export default {
margin-top: 2px;
width: 20px;
background-position: -100px 0;
&:hover {
}
}
.el-icon-video-camera {
@ -1014,6 +1256,68 @@ export default {
opacity: 0;
}
.floating-consult {
position: fixed;
right: 18px;
bottom: 128px;
z-index: 100;
}
.floating-consult-btn {
display: inline-flex;
align-items: center;
flex-direction: column;
text-decoration: none;
background: #ffffff;
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.14);
transition: all 0.25s ease;
}
.floating-consult-btn:hover {
transform: translateY(-3px);
box-shadow: 0 10px 24px rgba(0, 0, 0, 0.2);
}
.floating-consult-btn.primary {
width: 80px;
height: 80px;
padding: 12px 8px;
border-radius: 50%;
gap: 8px;
}
.floating-consult-icon {
position: relative;
width: 100%;
height: 100%;
}
.floating-consult-icon img {
width: 100%;
// height: 100%;
object-fit: cover;
border-radius: 50%;
}
.consult-badge {
position: absolute;
top: -2px;
right: -2px;
width: 10px;
height: 10px;
border-radius: 50%;
border: 2px solid #fff;
background: #ef4444;
}
.floating-consult-text {
writing-mode: vertical-rl;
text-orientation: mixed;
font-size: 12px;
color: #1f2937;
letter-spacing: 2px;
}
</style>
<style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

View File

@ -631,7 +631,7 @@ export default {
<style scoped lang="scss">
.message-center-wrapper {
position: relative;
z-index: 10000;
z-index:999999999999999999999!important;
}
.drawer, .drawerMobile {
@ -790,4 +790,228 @@ export default {
::v-deep .el-drawer__body {
overflow: auto;
}
/* 新版站内信视觉优化 */
.drawer,
.drawerMobile {
::v-deep .el-drawer {
background: #f5f8ff;
box-shadow: -18px 0 48px rgba(15, 23, 42, 0.16);
}
}
.drawer {
::v-deep .el-drawer {
width: 64% !important;
min-width: 860px;
border-radius: 24px 0 0 24px;
overflow: hidden;
}
}
.drawerMobile {
::v-deep .el-drawer {
border-radius: 18px 0 0 18px;
overflow: hidden;
}
}
.drawer ::v-deep .el-container,
.drawerMobile ::v-deep .el-container {
background: transparent;
}
.aside {
background: linear-gradient(180deg, #eef5ff 0%, #f8fbff 100%) !important;
border-right: 1px solid #e4ecf7;
.header {
height: 78px !important;
padding-left: 26px !important;
display: flex;
align-items: center;
background: transparent !important;
border-bottom: 0 !important;
color: #111827;
font-size: 20px !important;
line-height: 1.3 !important;
font-weight: 800 !important;
}
.title {
padding: 8px 14px;
div {
height: 44px !important;
margin-bottom: 8px;
padding-left: 16px !important;
display: flex;
align-items: center;
border-radius: 12px;
color: #5f6b7a;
font-size: 15px !important;
line-height: 44px !important;
font-weight: 600;
transition: all 0.2s ease;
&:hover {
background: rgba(30, 111, 255, 0.08) !important;
color: #1e6fff;
}
&.active {
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%) !important;
color: #fff !important;
box-shadow: 0 10px 24px rgba(39, 90, 255, 0.2);
}
}
}
}
.content_box {
padding: 22px 26px !important;
background: #f8fbff !important;
.header {
height: auto !important;
padding: 0 0 18px !important;
border-bottom: 0 !important;
color: #111827 !important;
font-size: 24px !important;
line-height: 1.35 !important;
font-weight: 800 !important;
}
.content {
padding: 0 !important;
}
.button {
margin-bottom: 16px !important;
padding: 14px 16px !important;
display: flex !important;
gap: 10px;
align-items: center;
border: 1px solid #edf1f7 !important;
border-radius: 16px;
background: #fff;
box-shadow: 0 10px 28px rgba(31, 45, 61, 0.05);
}
.msgtext {
margin: 4px 12px 12px;
padding: 16px 18px !important;
border: 1px solid #e8eef7;
border-radius: 14px !important;
background: #f7faff !important;
color: #4b5563 !important;
font-size: 14px;
line-height: 1.8 !important;
}
}
::v-deep .el-button {
border-radius: 999px;
font-weight: 600;
}
::v-deep .el-button--primary {
border-color: transparent;
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
}
::v-deep .el-button--danger {
border-color: #fee2e2;
background: #fff5f5;
color: #ef4444;
&:hover,
&:focus {
border-color: #fecaca;
background: #fee2e2;
color: #dc2626;
}
}
::v-deep .el-table {
border-radius: 18px;
overflow: hidden;
background: #fff;
box-shadow: 0 12px 32px rgba(31, 45, 61, 0.06);
&::before {
display: none;
}
th {
background: #f4f8ff !important;
color: #4b5563;
font-size: 14px;
font-weight: 700;
}
td {
border-bottom: 1px solid #edf1f7;
color: #344054;
font-size: 14px;
}
.el-table__row {
transition: background 0.2s ease;
&:hover > td {
background: #f7faff !important;
}
}
.el-table__expanded-cell {
background: #fff !important;
}
}
::v-deep .unReadColor td {
background: #eef5ff !important;
color: #111827;
font-weight: 600;
&:first-child {
position: relative;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
width: 4px;
height: 28px;
border-radius: 0 999px 999px 0;
background: #1e6fff;
transform: translateY(-50%);
}
}
}
@media (max-width: 768px) {
.content_box {
padding: 16px !important;
}
.aside {
.header {
height: 64px !important;
padding-left: 14px !important;
font-size: 16px !important;
}
.title {
padding: 6px 8px;
div {
height: 40px !important;
padding-left: 10px !important;
font-size: 13px !important;
}
}
}
}
</style>

View File

@ -1,9 +1,5 @@
<template>
<el-card class="model-toolbar" shadow="never">
<div class="toolbar-left">
<h3>筛选模型</h3>
<p>按模型名称和类型快速定位目标模型</p>
</div>
<el-form class="toolbar-search" :model="searchForm" inline>
<el-form-item label="模型名称">
<el-input
@ -90,28 +86,12 @@ export default {
/deep/ .el-card__body {
display: flex;
align-items: center;
justify-content: space-between;
justify-content: flex-start;
gap: 16px;
padding: 18px 20px 2px;
}
}
.toolbar-left {
margin-bottom: 16px;
h3 {
margin: 0 0 6px;
color: #1f2d3d;
font-size: 18px;
}
p {
margin: 0;
color: #8a94a6;
font-size: 13px;
}
}
.toolbar-search {
display: flex;
flex-wrap: wrap;

View File

@ -0,0 +1,36 @@
import Vue from 'vue'
import VueI18n from 'vue-i18n'
import zhCN from './lang/zh-CN'
import enUS from './lang/en-US'
Vue.use(VueI18n)
const LOCALE_STORAGE_KEY = 'kboss-locale'
const getInitialLocale = () => {
const saved = localStorage.getItem(LOCALE_STORAGE_KEY)
if (saved && ['zh-CN', 'en-US'].includes(saved)) {
return saved
}
const browserLocale = (navigator.language || '').toLowerCase()
return browserLocale.startsWith('zh') ? 'zh-CN' : 'en-US'
}
const i18n = new VueI18n({
locale: getInitialLocale(),
fallbackLocale: 'zh-CN',
silentFallbackWarn: true,
messages: {
'zh-CN': zhCN,
'en-US': enUS
}
})
export const setLocale = (locale) => {
if (!['zh-CN', 'en-US'].includes(locale)) return
i18n.locale = locale
localStorage.setItem(LOCALE_STORAGE_KEY, locale)
}
export default i18n

View File

@ -0,0 +1,660 @@
{
"auto.k_891cafba": "",
"auto.k_29fc67": "",
"auto.k_327d9f": "",
"auto.k_48d6f4": "",
"auto.k_28bb9d": "",
"auto.k_34472b": "",
"auto.k_29027a": "",
"auto.k_3da8b5cf": "",
"auto.k_3229ac": "",
"auto.k_14d70425": "",
"auto.k_795a9612": "",
"auto.k_30a8c9": "",
"auto.k_28cc07": "",
"auto.k_bd43f04b": "",
"auto.k_22d8670d": "",
"auto.k_1d1c04e": "",
"auto.k_7496006f": "",
"auto.k_cb2e6721": "",
"auto.k_c0c369a8": "",
"auto.k_a1a8105b": "",
"auto.k_31834f3d": "",
"auto.k_2c4ede94": "",
"auto.k_eeda968e": "",
"auto.k_2a9cc4": "",
"auto.k_3461ae": "",
"auto.k_7c2b05b8": "",
"auto.k_feaf7d41": "",
"auto.k_58aa42ac": "",
"auto.k_51f71d17": "",
"auto.k_988a0efb": "",
"auto.k_8f8bf1af": "",
"auto.k_8d97e264": "",
"auto.k_bdace956": "",
"auto.k_192d834b": "",
"auto.k_1b16d216": "",
"auto.k_3cc2fb06": "",
"auto.k_341253f0": "",
"auto.k_d8147332": "",
"auto.k_1551fea3": "",
"auto.k_cc1add49": "",
"auto.k_5315a0dd": "",
"auto.k_31d2df1d": "",
"auto.k_f194e5f8": "",
"auto.k_126ccc6": "",
"auto.k_4d85c3ff": "",
"auto.k_552000a3": "",
"auto.k_64e4c3bf": "",
"auto.k_3c6e36b8": "",
"auto.k_e2a292d8": "",
"auto.k_4f3037": "",
"auto.k_35ac63": "",
"auto.k_2aabf9": "",
"auto.k_1a429b71": "",
"auto.k_293328": "",
"auto.k_8e0bc8c2": "",
"auto.k_615b8010": "",
"auto.k_dcecac91": "",
"auto.k_a5572a20": "",
"auto.k_bd092bbd": "",
"auto.k_d19abc70": "",
"auto.k_d272d310": "",
"auto.k_6c336bfe": "",
"auto.k_1050670b": "",
"auto.k_e1fce560": "",
"auto.k_27cc0ccb": "",
"auto.k_74d74a41": "",
"auto.k_a2639d12": "",
"auto.k_dd08bc69": "",
"auto.k_cb2b5896": "",
"auto.k_5e1ef378": "",
"auto.k_206a58ba": "",
"auto.k_8289899a": "",
"auto.k_544cf4b1": "",
"auto.k_e32c9c98": "",
"auto.k_24b901c1": "",
"auto.k_1ad03f78": "",
"auto.k_c7813c60": "",
"auto.k_2bce4783": "",
"auto.k_4e91": "",
"auto.k_3d0120": "",
"auto.k_42455a55": "",
"auto.k_8ba373fd": "",
"auto.k_5995ec3a": "",
"auto.k_fb33053a": "",
"auto.k_5759c744": "",
"auto.k_af34ff13": "",
"auto.k_7f04b1a": "",
"auto.k_ec23c1ce": "",
"auto.k_4d7409": "",
"auto.k_1ac320cd": "",
"auto.k_b1d9c918": "",
"auto.k_7b97": "",
"auto.k_1b14c6c0": "",
"auto.k_30c18b77": "",
"auto.k_2d282a0f": "",
"auto.k_48e6a6": "",
"auto.k_2cd21e": "",
"auto.k_bcda23b4": "",
"auto.k_6e189720": "",
"auto.k_30dae4": "",
"auto.k_279817a5": "",
"auto.k_52b4a278": "",
"auto.k_77e4f5dc": "",
"auto.k_170de5bf": "",
"auto.k_af914b13": "",
"auto.k_69702517": "",
"auto.k_b1d74140": "",
"auto.k_3a80b42b": "",
"auto.k_e14e03d1": "",
"auto.k_2361a355": "",
"auto.k_6c48839e": "",
"auto.k_30c78b0f": "",
"auto.k_b8ee4174": "",
"auto.k_ea5b8e0": "",
"auto.k_aaafe392": "",
"auto.k_19c6d222": "",
"auto.k_cb5dc335": "",
"auto.k_97ab7077": "",
"auto.k_dc78b0c2": "",
"auto.k_dc7baebe": "",
"auto.k_b474c562": "",
"auto.k_1f37e1f1": "",
"auto.k_47eefa": "",
"auto.k_2e876c4": "",
"auto.k_58e0135b": "",
"auto.k_3f77dd6c": "",
"auto.k_2e720de": "",
"auto.k_8f027a0d": "",
"auto.k_fd935ad1": "",
"auto.k_f6b40e2d": "",
"auto.k_4e149994": "",
"auto.k_acc9ebb7": "",
"auto.k_e26dfe8c": "",
"auto.k_4b1ebc1": "",
"auto.k_1781f907": "",
"auto.k_41a54f": "",
"auto.k_9794bd0c": "",
"auto.k_1dd7191": "",
"auto.k_c6ad4dee": "",
"auto.k_14cfe6b3": "",
"auto.k_875e0d62": "",
"auto.k_61b226ea": "",
"auto.k_73860793": "",
"auto.k_8365f72f": "",
"auto.k_41d91a6d": "",
"auto.k_31bb079b": "",
"auto.k_b861886d": "",
"auto.k_14d9acd2": "",
"auto.k_f3c73ada": "",
"auto.k_3445de83": "",
"auto.k_180658a3": "",
"auto.k_b5ed3ba5": "",
"auto.k_1a904564": "",
"auto.k_be3c2fcd": "",
"auto.k_88d870e0": "",
"auto.k_f406d34f": "",
"auto.k_2e10a10a": "",
"auto.k_3887546": "",
"auto.k_3152a02e": "",
"auto.k_4729056c": "",
"auto.k_fe7c5a9d": "",
"auto.k_e84f851c": "",
"auto.k_ac895890": "",
"auto.k_28b7620d": "",
"auto.k_a9efcd7e": "",
"auto.k_b5c61b25": "",
"auto.k_623ab7e3": "",
"auto.k_91802ce6": "",
"auto.k_d39f9214": "",
"auto.k_efa0199a": "",
"auto.k_4ca1a150": "",
"auto.k_f0a9644a": "",
"auto.k_eccb7d4f": "",
"auto.k_6e1fd227": "",
"auto.k_e4dbd25c": "",
"auto.k_1297cbe0": "",
"auto.k_9da6ef72": "",
"auto.k_a22b37dd": "",
"auto.k_15b2dafa": "",
"auto.k_7fc3f48d": "",
"auto.k_b189dafd": "",
"auto.k_2f0eb0": "",
"auto.k_7a415bee": "",
"auto.k_7b42b269": "",
"auto.k_64895c5e": "",
"auto.k_c783fbbf": "",
"auto.k_14d0f7b4": "",
"auto.k_91acf74a": "",
"auto.k_1681c499": "",
"auto.k_6fa0041c": "",
"auto.k_48f4deb": "",
"auto.k_79a416dd": "",
"auto.k_f7a73da5": "",
"auto.k_2016d77a": "",
"auto.k_3953269a": "",
"auto.k_96329223": "",
"auto.k_49788c91": "",
"auto.k_4f88509": "",
"auto.k_587d0ad1": "",
"auto.k_f7bded03": "",
"auto.k_858d9a52": "",
"auto.k_d6607bc0": "",
"auto.k_22bc667f": "",
"auto.k_87c433ad": "",
"auto.k_538e9365": "",
"auto.k_d7e87dbc": "",
"auto.k_253638e1": "",
"auto.k_76ccce9f": "",
"auto.k_f7bd5263": "",
"auto.k_a2d2fbce": "",
"auto.k_6a69cdd3": "",
"auto.k_2b1aeee8": "",
"auto.k_6eb145e": "",
"auto.k_49cc9fc5": "",
"auto.k_2811096e": "",
"auto.k_de3f1ff0": "",
"auto.k_9d0896b7": "",
"auto.k_14f55b7f": "",
"auto.k_ed3581e5": "",
"auto.k_10cff6ef": "",
"auto.k_612fa110": "",
"auto.k_e5893350": "",
"auto.k_7eb1def7": "",
"auto.k_d028bec3": "",
"auto.k_14f6c91a": "",
"auto.k_9627760e": "",
"auto.k_541526f1": "",
"auto.k_e76a3725": "",
"auto.k_de4e6267": "",
"auto.k_63fbbb0": "",
"auto.k_2cad0ec0": "",
"auto.k_c6c313b4": "",
"auto.k_3c86dc7b": "",
"auto.k_b2e7e749": "",
"auto.k_27bc48d6": "",
"auto.k_910aa69": "",
"auto.k_4d05d789": "",
"auto.k_69262afb": "",
"auto.k_b685fcc5": "",
"auto.k_8e5616a8": "",
"auto.k_bd8bee8e": "",
"auto.k_a9ddc96f": "",
"auto.k_bd721723": "",
"auto.k_bd77cd87": "",
"auto.k_1f200547": "",
"auto.k_bd83c5ab": "",
"auto.k_5108ee01": "",
"auto.k_aaaba2f0": "",
"auto.k_647e5318": "",
"auto.k_69293704": "",
"auto.k_aeafa813": "",
"auto.k_a8f11c0e": "",
"auto.k_ebe13d08": "",
"auto.k_9e3042e2": "",
"auto.k_5bea967e": "",
"auto.k_752bbb7b": "",
"auto.k_7c548e20": "",
"auto.k_d9a10d6e": "",
"auto.k_734a3f18": "",
"auto.k_96c41446": "",
"auto.k_69493a93": "",
"auto.k_3e40e91b": "",
"auto.k_aea16be7": "",
"auto.k_a672ab23": "",
"auto.k_cf6d5913": "",
"auto.k_9415928": "",
"auto.k_5933138d": "",
"auto.k_7d354326": "",
"auto.k_61a625d7": "",
"auto.k_9e5421e4": "",
"auto.k_189c9a71": "",
"auto.k_598ccbff": "",
"auto.k_affca802": "",
"auto.k_a2375f74": "",
"auto.k_106ec8a4": "",
"auto.k_27ff77f3": "",
"auto.k_84ddf22e": "",
"auto.k_161a9453": "",
"auto.k_63b358d5": "",
"auto.k_71d117bc": "",
"auto.k_d92ba6f6": "",
"auto.k_dbe551dc": "",
"auto.k_72244a06": "",
"auto.k_e5bab477": "",
"auto.k_d2c29f9a": "",
"auto.k_3584db55": "",
"auto.k_61317c38": "",
"auto.k_104149bd": "",
"auto.k_45024589": "",
"auto.k_f080b461": "",
"auto.k_87fdacd8": "",
"auto.k_ab7dbe91": "",
"auto.k_cbf52e56": "",
"auto.k_64bdf283": "",
"auto.k_7b724627": "",
"auto.k_14a94485": "",
"auto.k_d4f36be9": "",
"auto.k_85c28bd7": "",
"auto.k_f8d6a93d": "",
"auto.k_42e9d7": "",
"auto.k_a2a31a94": "",
"auto.k_bc6cfe59": "",
"auto.k_a3fc5d82": "",
"auto.k_dd5895b2": "",
"auto.k_f097392b": "",
"auto.k_f9a42196": "",
"auto.k_f071b753": "",
"auto.k_9f1adb46": "",
"auto.k_3b399598": "",
"auto.k_59ab505": "",
"auto.k_dd492beb": "",
"auto.k_df497eec": "",
"auto.k_bc6452c6": "",
"auto.k_7528": "",
"auto.k_8f9acd0": "",
"auto.k_d4f12c45": "",
"auto.k_47b0bfd2": "",
"auto.k_d4f56a70": "",
"auto.k_f408eb81": "",
"auto.k_a92e329a": "",
"auto.k_352eddc": "",
"auto.k_daf7aae1": "",
"auto.k_7c28eb07": "",
"auto.k_aa27f4e7": "",
"auto.k_96951162": "",
"auto.k_ea56e1": "",
"auto.k_fe16d0e4": "",
"auto.k_94c8b040": "",
"auto.k_a31259b8": "",
"auto.k_3e161c": "",
"auto.k_e5a8dbbb": "",
"auto.k_c64270f2": "",
"auto.k_643828c3": "",
"auto.k_2284ccee": "",
"auto.k_5ffabcfd": "",
"auto.k_220c3f9": "",
"auto.k_2745ae63": "",
"auto.k_4291145b": "",
"auto.k_22e55078": "",
"auto.k_133624f8": "",
"auto.k_b2b2364a": "",
"auto.k_24f0a833": "",
"auto.k_91a3f213": "",
"auto.k_c35ea6c8": "",
"auto.k_664081f9": "",
"auto.k_b128381d": "",
"auto.k_b43f4db": "",
"auto.k_362d4a34": "",
"auto.k_e1af0e94": "",
"auto.k_2b540a": "",
"auto.k_b0e3ed6": "",
"auto.k_c873be5e": "",
"auto.k_ab0ae497": "",
"auto.k_5b04603f": "",
"auto.k_325715": "",
"auto.k_ee44bed0": "",
"auto.k_4afc0673": "",
"auto.k_7d7b12f1": "",
"auto.k_1dc10570": "",
"auto.k_cb4e1ce7": "",
"auto.k_e599994b": "",
"auto.k_7acbbb23": "",
"auto.k_26d9a8e6": "",
"auto.k_125a8015": "",
"auto.k_8d312c1": "",
"auto.k_8a354dce": "",
"auto.k_289436": "",
"auto.k_46e788": "",
"auto.k_a67785a6": "",
"auto.k_2ae297": "",
"auto.k_2ada03": "",
"auto.k_ac772764": "",
"auto.k_c2320676": "",
"auto.k_370086d7": "",
"auto.k_baecb079": "",
"auto.k_f469434a": "",
"auto.k_d22bec33": "",
"auto.k_9eda5fe4": "",
"auto.k_13deb0b8": "",
"auto.k_2ac85a": "",
"auto.k_2d091d": "",
"auto.k_284e38": "",
"auto.k_f5601a4f": "",
"auto.k_74a58c8e": "",
"auto.k_5853242f": "",
"auto.k_cdbe77bb": "",
"auto.k_61431881": "",
"auto.k_71ad3b1d": "",
"auto.k_82ce5ab4": "",
"auto.k_71b1a3b2": "",
"auto.k_82d2c349": "",
"auto.k_ff2f20b3": "",
"auto.k_68d77110": "",
"auto.k_71c974d2": "",
"auto.k_82ea9469": "",
"auto.k_93c8f976": "",
"auto.k_9177df70": "",
"auto.k_15f4726e": "",
"auto.k_1a235154": "",
"auto.k_380c44": "",
"auto.k_3d0046": "",
"auto.k_63cc4f1b": "",
"auto.k_35a13a": "",
"auto.k_645a22e8": "",
"auto.k_a94ced38": "",
"auto.k_bde6eceb": "",
"auto.k_a06c662e": "",
"auto.k_52fb8a4e": "",
"auto.k_1702458a": "",
"auto.k_2622eacb": "",
"auto.k_1ef98f0e": "",
"auto.k_e7374136": "",
"auto.k_66a72d63": "",
"auto.k_79db82ad": "",
"auto.k_3227713d": "",
"auto.k_e4c2b952": "",
"auto.k_c7c24dde": "",
"auto.k_febb523e": "",
"auto.k_5f338c14": "",
"auto.k_71baf8df": "",
"auto.k_3e19749d": "",
"auto.k_1b7caeea": "",
"auto.k_93af09b6": "",
"auto.k_dd54984d": "",
"auto.k_1c6ca72e": "",
"auto.k_39b260aa": "",
"auto.k_7ce3cdb3": "",
"auto.k_42486b03": "",
"auto.k_c00a78b0": "",
"auto.k_aab35b7e": "",
"auto.k_bb7c1af2": "",
"auto.k_c27a8a4f": "",
"auto.k_72b75396": "",
"auto.k_e6acb5f5": "",
"auto.k_8a32a1f9": "",
"auto.k_27c68d0e": "",
"auto.k_4537b357": "",
"auto.k_a9ea2313": "",
"auto.k_9c3e78d3": "",
"auto.k_cd74d141": "",
"auto.k_1132219e": "",
"auto.k_aac50534": "",
"auto.k_e5e4cfc2": "",
"auto.k_f1221458": "",
"auto.k_86134e4d": "",
"auto.k_25754cff": "",
"auto.k_cd88a94a": "",
"auto.k_eb46f365": "",
"auto.k_32a537": "",
"auto.k_2a1ac1": "",
"auto.k_3c9751e": "",
"auto.k_aab4a718": "",
"auto.k_aad660c7": "",
"auto.k_baeeec74": "",
"auto.k_a1eddfe1": "",
"auto.k_6f67cfbd": "",
"auto.k_28aa87": "",
"auto.k_349fa1": "",
"auto.k_2a7690": "",
"auto.k_a74524f2": "",
"auto.k_4160fbc6": "",
"auto.k_31b4332c": "",
"auto.k_bd006e6b": "",
"auto.k_387935": "",
"auto.k_47da65": "",
"auto.k_fad13012": "",
"auto.k_7e289a88": "",
"auto.k_15549c58": "",
"auto.k_b2a6b283": "",
"auto.k_492a27ef": "",
"auto.k_c79c4402": "",
"auto.k_5a32928e": "",
"auto.k_15876aef": "",
"auto.k_e0aece92": "",
"auto.k_b1e63470": "",
"auto.k_218157b6": "",
"auto.k_50087452": "",
"auto.k_536b7c75": "",
"auto.k_f8bec61d": "",
"auto.k_18cdf3f3": "",
"auto.k_247766b8": "",
"auto.k_ecccd5e8": "",
"auto.k_5717a506": "",
"auto.k_94053235": "",
"auto.k_68d873d6": "",
"auto.k_662f": "",
"auto.k_5426": "",
"auto.k_837ffdcc": "",
"auto.k_8aed99a4": "",
"auto.k_2836c0fa": "",
"auto.k_42b89b2a": "",
"auto.k_aab42c1c": "",
"auto.k_145c7c79": "",
"auto.k_ff43a938": "",
"auto.k_21dac21f": "",
"auto.k_41f985": "",
"auto.k_34574d3a": "",
"auto.k_46f550d9": "",
"auto.k_b09da136": "",
"auto.k_4a84bb": "",
"auto.k_ed30e0c0": "",
"auto.k_e9503cf2": "",
"auto.k_b44d40bf": "",
"auto.k_2a1267": "",
"auto.k_6e3ad284": "",
"auto.k_fa841a03": "",
"auto.k_20fb78c8": "",
"auto.k_adb9e27": "",
"auto.k_1ac33912": "",
"auto.k_1a34bec1": "",
"auto.k_4179d4": "",
"auto.k_8f1efc59": "",
"auto.k_28d0a1": "",
"auto.k_867ade4d": "",
"auto.k_336214": "",
"auto.k_4b1b55": "",
"auto.k_47f5228b": "",
"auto.k_2a43c6": "",
"auto.k_8384236c": "",
"auto.k_c64df876": "",
"auto.k_c656409d": "",
"auto.k_5a33916e": "",
"auto.k_4a7fde7e": "",
"auto.k_17969e06": "",
"auto.k_24786598": "",
"auto.k_64b56d7d": "",
"auto.k_52f254f7": "",
"auto.k_4f895e25": "",
"auto.k_21c3ae29": "",
"auto.k_fa9835f6": "",
"auto.k_99d8b33b": "",
"auto.k_67fd7e9": "",
"auto.k_33b776": "",
"auto.k_2bf793": "",
"auto.k_4db142": "",
"auto.k_e54e3309": "",
"auto.k_295351": "",
"auto.k_30b237": "",
"auto.k_3a5f2f": "",
"auto.k_424a5fcc": "",
"auto.k_ab86def2": "",
"auto.k_18837bab": "",
"auto.k_30c7d0c7": "",
"auto.k_541664e8": "",
"auto.k_5855557f": "",
"auto.k_52fd7969": "",
"auto.k_74c75ff6": "",
"auto.k_85311a0a": "",
"auto.k_d738ab54": "",
"auto.k_1189154d": "",
"auto.k_d59dcad7": "",
"auto.k_c1fda5dc": "",
"auto.k_c044dbba": "",
"auto.k_ad55e119": "",
"auto.k_2f820a2b": "",
"auto.k_808ebef8": "",
"auto.k_ac2ddc78": "",
"auto.k_ac9aa2b9": "",
"auto.k_bf4a273c": "",
"auto.k_afcf61c4": "",
"auto.k_fe188949": "",
"auto.k_a0376a5": "",
"auto.k_cf1b89e2": "",
"auto.k_536f6162": "",
"auto.k_cc0ac7bd": "",
"auto.k_b49f92b": "",
"auto.k_3ff654ca": "",
"auto.k_2b6eda08": "",
"auto.k_aeb7ac7f": "",
"auto.k_ea3dfa7e": "",
"auto.k_b29c24b3": "",
"auto.k_ee00f23e": "",
"auto.k_d57ff6f7": "",
"auto.k_1deb1ba9": "",
"auto.k_bf08053a": "",
"auto.k_39df1a": "",
"auto.k_1b17d914": "",
"auto.k_8e1675a": "",
"auto.k_5867ab46": "",
"auto.k_2c77c8b5": "",
"auto.k_67cb5d9f": "",
"auto.k_ded5e6af": "",
"auto.k_31730c52": "",
"auto.k_d49699d7": "",
"auto.k_61c17c32": "",
"auto.k_9f4d84fd": "",
"auto.k_8f9d9457": "",
"auto.k_26f505f7": "",
"auto.k_42421d1c": "",
"auto.k_ded503f7": "",
"auto.k_d16cb8ea": "",
"auto.k_1215e93": "",
"auto.k_8863e66c": "",
"auto.k_5dd248f7": "",
"auto.k_85c391cf": "",
"auto.k_b2f352d8": "",
"auto.k_43bc0bf6": "",
"auto.k_a7f1b764": "",
"auto.k_9c250921": "",
"auto.k_3b1964a6": "",
"auto.k_22f6d914": "",
"auto.k_15aa11f4": "",
"auto.k_b25ac853": "",
"auto.k_afcd4037": "",
"auto.k_283d2d38": "",
"auto.k_a5e6221e": "",
"auto.k_63d17817": "",
"auto.k_c6754278": "",
"auto.k_b8c235d8": "",
"auto.k_e1caab02": "",
"auto.k_362db66d": "",
"auto.k_7c688629": "",
"auto.k_337155c7": "",
"auto.k_e66edb6b": "",
"auto.k_134c1ad3": "",
"auto.k_362199d0": "",
"auto.k_eb95efe5": "",
"auto.k_d278f148": "",
"auto.k_e12e47cc": "",
"auto.k_b19ec9a0": "",
"auto.k_89fe0d8d": "",
"auto.k_19822ae1": "",
"auto.k_68236277": "",
"auto.k_208c3db": "",
"auto.k_8a1881": "",
"auto.k_8794934d": "",
"auto.k_af7cfce": "",
"auto.k_a21fa305": "",
"auto.k_2b75ed8a": "",
"auto.k_267fed08": "",
"auto.k_11e65c52": "",
"auto.k_c4d3d3bb": "",
"auto.k_b0d93aac": "",
"auto.k_f6531a01": "",
"auto.k_47a4d84": "",
"auto.k_ca80787e": "",
"auto.k_56c64dae": "",
"auto.k_ba1e3e13": "",
"auto.k_30ce450f": "",
"auto.k_541b360e": "",
"auto.k_52f15617": "",
"auto.k_124c904e": "",
"auto.k_9d88781a": "",
"auto.k_3cf92dee": "",
"auto.k_71aa1959": "",
"auto.k_77b520f5": "",
"auto.k_331ee0b2": "",
"auto.k_404e5419": "",
"auto.k_46674ba": "",
"auto.k_cc18530c": "",
"auto.k_5848c1e4": "",
"auto.k_b49e100": "",
"auto.k_34fc9f": "",
"auto.k_dfd2620b": "",
"auto.k_2b3137": "",
"auto.k_83d7e8fa": "",
"auto.k_b3f0ee98": "",
"auto.k_66c24902": ""
}

View File

@ -0,0 +1,97 @@
import autoMessages from './en-US.auto.json'
export default {
common: {
language: 'Language',
chinese: 'Chinese',
english: 'English'
},
topbar: {
home: 'Home',
product: 'Products',
cases: 'Use Cases',
news: 'News',
login: 'Login',
registerNow: 'Sign Up',
console: 'Console',
switchZhSuccess: 'Switched to Chinese',
switchEnSuccess: 'Switched to English'
},
home: {
heroTitle: 'One Platform · Intelligent Leap · Across All Industries.',
heroSubtitle: '',
heroSlogan: 'Make AI Everywhere, Make AI Easy',
solutionsBtn: 'Solutions',
contactSalesBtn: 'Contact Sales',
aiSolutionsTitle: 'AI + Solutions',
successCasesTitle: 'Use Cases',
moreCases: 'View All Use Cases →',
ctaTitle: 'How Do These Solutions Work in Practice?',
ctaDesc: 'Get industry-specific AI solutions.',
contactUsArrow: 'Contact Us →',
companyNewsTitle: 'Company News',
viewMore: 'View More →',
footerProducts: 'Products & Services',
footerContact: 'Contact Us',
onlineChat: 'Online Chat',
solutionCards: {
collaboration: {
title: 'Collaborative Intelligence',
subtitle: 'Multi-Agent Coordination'
},
spatial: {
title: 'Spatial Intelligence',
subtitle: 'GIS Smart Analysis'
},
predictive: {
title: 'Predictive Insight',
subtitle: 'Intelligent Forecasting Engine'
},
vision: {
title: 'Microscopic Insight',
subtitle: 'Machine Vision Inspection'
},
qa: {
title: 'Instant Answers',
subtitle: 'Intelligent Q&A Knowledge Base'
},
protection: {
title: 'Continuous Protection',
subtitle: 'Intelligent Device Monitoring'
},
document: {
title: 'Document Intelligence',
subtitle: 'Smart Document Parsing'
},
edge: {
title: 'Edge Intelligence',
subtitle: 'Edge AI Inference'
}
},
cases: {
railway: {
name: 'China Railway Group · AI Industry Bidding Agent Engine',
title: 'Smart Engineering',
desc: 'AI-Powered Bidding Process'
},
forestry: {
name: 'Nanning Forestry Bureau · Smart Harvesting',
title: 'Smart Harvesting',
desc: 'AI-Powered Forestry Spatial Intelligence Review'
},
beigang: {
name: 'AI Empowerment · Beibu Gulf Big Data',
title: 'Digital & Intelligent Upgrade',
desc: 'Three Core AI Agent Platforms'
}
},
news: {
tag: 'Company News',
firstTitle: 'Open Computing AI Visits ASEAN with CCPIT',
firstDesc: 'Open Computing AI joined the CCPIT Guangxi branch delegation on business visits to Vietnam and Laos, where it engaged in deep discussions on AI agent deployment, cross-border digital infrastructure cooperation, and smart city solutions — further expanding its footprint in Southeast Asian markets.',
secondTitle: 'Open Computing AI Named Forbes China AI Commercial Application Demonstration Enterprise',
secondDesc: 'Recognized for its industrial-grade AI agent factory delivery capabilities and benchmark cases among central and state-owned enterprises, Open Computing AI was named a Forbes China AI Commercial Application Demonstration Enterprise — underscoring its leadership in turning AI technology into scalable, real-world industry solutions.'
}
},
...autoMessages
}

View File

@ -0,0 +1,660 @@
{
"auto.k_891cafba": "全球领先的AI服务运营商",
"auto.k_29fc67": "关于",
"auto.k_327d9f": "我们",
"auto.k_48d6f4": "资质",
"auto.k_28bb9d": "企业",
"auto.k_34472b": "文化",
"auto.k_29027a": "使命",
"auto.k_3da8b5cf": "让AI无处不在让智能如此简单",
"auto.k_3229ac": "愿景",
"auto.k_14d70425": "价值观",
"auto.k_795a9612": "卓越、开放、创新",
"auto.k_30a8c9": "平台",
"auto.k_28cc07": "优势",
"auto.k_bd43f04b": "使命图标",
"auto.k_22d8670d": "愿景图标",
"auto.k_1d1c04e": "价值观图标",
"auto.k_7496006f": "合同智能审查",
"auto.k_cb2e6721": "应用场景",
"auto.k_c0c369a8": "覆盖企业合同全生命周期审核链路",
"auto.k_a1a8105b": "业务合同初审",
"auto.k_31834f3d": "自动解析购销、服务、租赁、合作类通用业务合同,逐条对标企业风控红线快速筛查风险点,输出初审意见,减轻法务基础审核工作量,快速完成业务前置审批。",
"auto.k_2c4ede94": "复杂商事合同深度风控",
"auto.k_eeda968e": "针对投融资、知识产权、工程、保密竞业等高风险专项合同,联动完整法条与司法判例开展多层级风险推演,梳理权责漏洞、违约缺陷、管辖争议等深层隐患,输出完整风控评估文档。",
"auto.k_2a9cc4": "删除",
"auto.k_3461ae": "新增",
"auto.k_7c2b05b8": "多方合同版本比对修订",
"auto.k_feaf7d41": "自动识别甲乙双方多轮修改稿件差异,区分新增、删减、修改条款,高亮标注风险变更内容,同步生成版本对比台账,辅助商务谈判与法务复核,避免改稿遗漏关键风险。",
"auto.k_58aa42ac": "企业合同管理的困境与解决方案",
"auto.k_51f71d17": "围绕数据归集、合同编审、知识沉淀、智能咨询四大核心维度",
"auto.k_988a0efb": "现存困境",
"auto.k_8f8bf1af": "解决方案",
"auto.k_8d97e264": "项目亮点",
"auto.k_bdace956": "全流程智能风控,四大核心审查能力落地",
"auto.k_192d834b": "投策智能体",
"auto.k_1b16d216": "覆盖企业投资决策全链路",
"auto.k_3cc2fb06": "企业决策的困境与解决方案",
"auto.k_341253f0": "聚焦数据收集、研报撰写、知识管理、智能应用四大维度",
"auto.k_d8147332": "一次研究,双格式交付",
"auto.k_1551fea3": "开始使用投策智能体",
"auto.k_cc1add49": "让AI赋能您的投资决策一次研究双格式交付",
"auto.k_5315a0dd": "联系销售",
"auto.k_31d2df1d": "智能体商店",
"auto.k_f194e5f8": "需要定制智能体?",
"auto.k_126ccc6": "告诉我们您的业务场景我们将为您打造专属的AI智能体解决方案",
"auto.k_4d85c3ff": "京公网安备11010502054007",
"auto.k_552000a3": "../../assets/kyy/深入方案bg.png",
"auto.k_64e4c3bf": "../../assets/kyy/编组_10.png",
"auto.k_3c6e36b8": "../../assets/kyy/客服wechat.png",
"auto.k_e2a292d8": "../../assets/kyy/kyy公众号.jpg",
"auto.k_4f3037": "首页",
"auto.k_35ac63": "案例",
"auto.k_2aabf9": "动态",
"auto.k_1a429b71": "控制台",
"auto.k_293328": "余额",
"auto.k_8e0bc8c2": "个人中心",
"auto.k_615b8010": "退出登录",
"auto.k_dcecac91": "精选产品",
"auto.k_a5572a20": "算力市场",
"auto.k_bd092bbd": "Token市集",
"auto.k_d19abc70": "训推平台",
"auto.k_d272d310": "供需广场",
"auto.k_6c336bfe": "覆盖模型服务、算力资源、智能体应用与供需协同",
"auto.k_1050670b": "核心服务",
"auto.k_e1fce560": "一站式 AI 模型交易与服务平台",
"auto.k_27cc0ccb": "创镱工坊",
"auto.k_74d74a41": "AI 驱动的创意影像创作平台",
"auto.k_a2639d12": "云枢基座",
"auto.k_dd08bc69": "企业级 AI 基础设施与算力底座",
"auto.k_cb2b5896": "应用入口",
"auto.k_5e1ef378": "高性能算力资源灵活选购",
"auto.k_206a58ba": "AI 模型全流程开发体验",
"auto.k_8289899a": "即开即用的智能体服务",
"auto.k_544cf4b1": "资源、算力、服务供需匹配",
"auto.k_e32c9c98": "有问题,找开元",
"auto.k_24b901c1": "我是开元智能助手,可以为您解答算力服务器选型、采购、部署和资源配置等问题。",
"auto.k_1ad03f78": "新对话",
"auto.k_c7813c60": "Enter 发送",
"auto.k_2bce4783": "请输入你的问题",
"auto.k_4e91": "云",
"auto.k_3d0120": "百度",
"auto.k_42455a55": "大数据sdf平台",
"auto.k_8ba373fd": "弹性云服务器",
"auto.k_5995ec3a": "裸金属sd服务器",
"auto.k_fb33053a": "GPUsss少东风少东风云服务器",
"auto.k_5759c744": "大数据s少东风df平台",
"auto.k_af34ff13": "弹性云手动发服务器",
"auto.k_7f04b1a": "裸金属少东风服务器",
"auto.k_ec23c1ce": "GPU云少东风服务器",
"auto.k_4d7409": "阿里",
"auto.k_1ac320cd": "数据库",
"auto.k_b1d9c918": "数据库1",
"auto.k_7b97": "算",
"auto.k_1b14c6c0": "智算1",
"auto.k_30c18b77": "网络存储",
"auto.k_2d282a0f": "GPU云服务器",
"auto.k_48e6a6": "超算",
"auto.k_2cd21e": "国产",
"auto.k_bcda23b4": "国产超算",
"auto.k_6e189720": "通用计算",
"auto.k_30dae4": "应用",
"auto.k_279817a5": "灵医只能",
"auto.k_52b4a278": "存储服务",
"auto.k_77e4f5dc": "对象存储",
"auto.k_170de5bf": "块存储",
"auto.k_af914b13": "文件存储",
"auto.k_69702517": "备份与恢复",
"auto.k_b1d74140": "数据备份",
"auto.k_3a80b42b": "灾难恢复",
"auto.k_e14e03d1": "归档存储",
"auto.k_2361a355": "长期归档",
"auto.k_6c48839e": "低频访问存储",
"auto.k_30c78b0f": "网络服务",
"auto.k_b8ee4174": "虚拟私有云",
"auto.k_ea5b8e0": "负载均衡",
"auto.k_aaafe392": "内容分发网络",
"auto.k_19c6d222": "VPN与专线",
"auto.k_cb5dc335": "虚拟专用网络",
"auto.k_97ab7077": "专线连接",
"auto.k_dc78b0c2": "域名服务",
"auto.k_dc7baebe": "域名注册",
"auto.k_b474c562": "DNS解析",
"auto.k_1f37e1f1": "百度云",
"auto.k_47eefa": "计算",
"auto.k_2e876c4": "云服务器_GPU",
"auto.k_58e0135b": "既可提供弹性的GPU云服务器也可提供高性能的GPU裸金属服务器。",
"auto.k_3f77dd6c": "计算密集型,弹性高行能",
"auto.k_2e720de": "云服务器_BCC",
"auto.k_8f027a0d": "构建可弹性伸缩云计算服务,提供超高效费比的高性能云服务器。",
"auto.k_fd935ad1": "弹性伸缩,高性能",
"auto.k_f6b40e2d": "专属服务器",
"auto.k_4e149994": "提供性能可控、资源独享、物理资源隔离的专属云计算服务。",
"auto.k_acc9ebb7": "资源独享,专属云计算",
"auto.k_e26dfe8c": "轻量应用服务器",
"auto.k_4b1ebc1": "提供官网搭建、web应用搭建、云上学习和测试等场景的服务。",
"auto.k_1781f907": "多场景",
"auto.k_41a54f": "网络",
"auto.k_9794bd0c": "专线接入",
"auto.k_1dd7191": "专线是一种高性能、安全性极好的网络传输服务",
"auto.k_c6ad4dee": "高性能,安全性极好",
"auto.k_14cfe6b3": "云监控",
"auto.k_875e0d62": "提供7*24小时的实时监控服务为您的系统保驾护航。",
"auto.k_61b226ea": "实时监控",
"auto.k_73860793": "对等连接",
"auto.k_8365f72f": "实现同地域、跨地域,同账户、跨账户之间稳定高速的虚拟网络互联。",
"auto.k_41d91a6d": "高速的虚拟网络",
"auto.k_31bb079b": "智能云解析",
"auto.k_b861886d": "帮助企业和开发者通过域名就可以方便地访问到网站或应用服务器。",
"auto.k_14d9acd2": "云解析",
"auto.k_f3c73ada": "弹性公网IP",
"auto.k_3445de83": "为用户访问公网提供IP地址和公网带宽增加用户使用弹性。",
"auto.k_180658a3": "弹性,高可用",
"auto.k_b5ed3ba5": "负载均衡专属集群",
"auto.k_1a904564": "为客户提供高可用的流量分发服务,可以在多台云服务器之间进行均衡的应用流量分发",
"auto.k_be3c2fcd": "本地DNS服务",
"auto.k_88d870e0": "百度自研高性能DNS系统和IP调度技术",
"auto.k_f406d34f": "流量突发服务包",
"auto.k_2e10a10a": "轻松应对海量访问请求,实现业务水平扩展",
"auto.k_3887546": "多协议,高可用",
"auto.k_3152a02e": "IPv6公网网关",
"auto.k_4729056c": "为云服务器实现从内网IP到公网IP的多对一或多对多的地址转换服务。",
"auto.k_fe7c5a9d": "共享带宽",
"auto.k_e84f851c": "移动域名解析",
"auto.k_ac895890": "避免使用DNS所带来的域名劫持、解析不精准以及域名更新生效不及时等问题",
"auto.k_28b7620d": "高可用",
"auto.k_a9efcd7e": "提供区域级别的带宽共享及复用能力",
"auto.k_b5c61b25": "带宽共享",
"auto.k_623ab7e3": "NAT网关",
"auto.k_91802ce6": "智能流量管理",
"auto.k_d39f9214": "科学地自动止损、策略化分配流量、高效利用带宽资源。",
"auto.k_efa0199a": "EIP带宽包",
"auto.k_4ca1a150": "实现多个弹性公网IP共享网络带宽总量",
"auto.k_f0a9644a": "VPN网关",
"auto.k_eccb7d4f": "一款网络连接产品,满足业务交互、移动办公等应用场景。",
"auto.k_6e1fd227": "移动办公",
"auto.k_e4dbd25c": "服务网卡",
"auto.k_1297cbe0": "用户可以在VPC内或者混合云对端通过内网便捷、安全地访问服务",
"auto.k_9da6ef72": "混合云对端",
"auto.k_a22b37dd": "云智能网",
"auto.k_15b2dafa": "可实现全场景资源覆盖、分布式网络接入。",
"auto.k_7fc3f48d": "分布式网络",
"auto.k_b189dafd": "提供高可用的流量分发服务,轻松应对海量访问请求,实现业务水平扩展。",
"auto.k_2f0eb0": "存储",
"auto.k_7a415bee": "为云上的虚机、容器等计算资源提供无限扩展、高可靠、全球共享的文件存储能力",
"auto.k_7b42b269": "无限扩展,高可靠",
"auto.k_64895c5e": "提供稳定、安全、高效、高可拓展的云存储服务。",
"auto.k_c783fbbf": "安全,高扩展",
"auto.k_14d0f7b4": "云磁盘",
"auto.k_91acf74a": "提供的低时延、持久性、高可靠和高弹性的块存储服务。",
"auto.k_1681c499": "低时延,持久性",
"auto.k_6fa0041c": "由加速节点直接响应用户所需内容,提高用户访问网站资源的响应速度。",
"auto.k_48f4deb": "内容分发",
"auto.k_79a416dd": "数据可视化私有化",
"auto.k_f7a73da5": "可按需部署到企业本地服务器或私有云服务器,全面满足您对翻译精准度",
"auto.k_2016d77a": "私有化",
"auto.k_3953269a": "消息服务 for Kafka",
"auto.k_96329223": "即时插拔的方式,让您用最低的成本,享受最优质的消息服务。",
"auto.k_49788c91": "即时插拔",
"auto.k_4f88509": "云数据库RDS",
"auto.k_587d0ad1": "专业化的高可靠、高性能的关系型数据库服务。",
"auto.k_f7bded03": "高可靠,高性能",
"auto.k_858d9a52": "计算集群服务,提供高可靠、高安全性、高性价比的分布式计算服务",
"auto.k_d6607bc0": "计算集群",
"auto.k_22bc667f": "云数据库SCS for Redis",
"auto.k_87c433ad": "云数据库HBase",
"auto.k_538e9365": "支持PB规模、千万级并发、毫秒响应、低成本存储、全托管等企业级服务能力。",
"auto.k_d7e87dbc": "高并发,秒响应",
"auto.k_253638e1": "云数据库DocDB for MongoDB",
"auto.k_76ccce9f": "提供高可靠、高弹性、免运维的云上文档数据库服务",
"auto.k_f7bd5263": "高可靠,高弹性",
"auto.k_a2d2fbce": "大数据平台",
"auto.k_6a69cdd3": "日志服务BLS",
"auto.k_2b1aeee8": "帮助用户轻松应对服务运维管理、商业趋势洞察、安全监控审计等业务场景。",
"auto.k_6eb145e": "实时音视频",
"auto.k_49cc9fc5": "提供稳定高质量的实时音视频服务,帮助客户快速搭建多平台实时音视频应用。",
"auto.k_2811096e": "音视频",
"auto.k_de3f1ff0": "音视频处理",
"auto.k_9d0896b7": "提供稳定流畅、低延迟、支持高并发的一站式智能直播云服务。",
"auto.k_14f55b7f": "低延迟",
"auto.k_ed3581e5": "具备冷热分离、向量检索等产品特性。提供低成本、高性能和安全可靠的服务。",
"auto.k_10cff6ef": "冷热分离",
"auto.k_612fa110": "容器实例",
"auto.k_e5893350": "百度智能云容器实例为您提供Serverless的容器服务",
"auto.k_7eb1def7": "数据仓库DORIS",
"auto.k_d028bec3": "帮助企业快速且低成本地构建极速易用的云上数据分析平台。",
"auto.k_14f6c91a": "低成本",
"auto.k_9627760e": "泛CDN",
"auto.k_541526f1": "数据传输服务",
"auto.k_e76a3725": "利用实时同步通道轻松构建异地容灾的高可用数据库架构。",
"auto.k_de4e6267": "音视频直播",
"auto.k_63fbbb0": "低延迟,支持高并发",
"auto.k_2cad0ec0": "动态加速",
"auto.k_c6c313b4": "将动态内容以最优传输路径分发给用户,帮助网站显著提升访问体验",
"auto.k_3c86dc7b": "AI能力引擎",
"auto.k_b2e7e749": "文字识别",
"auto.k_27bc48d6": "广泛适用于远程身份认证、财税报销、文档电子化等场景,为企业降本增效",
"auto.k_910aa69": "AI识别",
"auto.k_4d05d789": "语音能力引擎",
"auto.k_69262afb": "广泛应用于语音播报,语音会议、智能语音交互等多个业务场景",
"auto.k_b685fcc5": "自然语言处理",
"auto.k_8e5616a8": "提供可直接进行场景应用的NLP语言生成能力帮助您在多领域快速创作",
"auto.k_bd8bee8e": "图像识别",
"auto.k_a9ddc96f": "精准识别超过十万种物体和场景",
"auto.k_bd721723": "图像处理",
"auto.k_bd77cd87": "图像搜索",
"auto.k_1f200547": "清晰等维度对图像进行筛选,紧贴业务需求,释放审核人力",
"auto.k_bd83c5ab": "图像筛选",
"auto.k_5108ee01": "卡证识别",
"auto.k_aaaba2f0": "结构化识别身份证、银行卡、营业执照等常用卡片及证照,支持营业执照信息的准确性核验",
"auto.k_647e5318": "图像增强与特效",
"auto.k_69293704": "满足网络营销、广告活动等多种业务需求",
"auto.k_aeafa813": "人脸识别",
"auto.k_a8f11c0e": "灵活应用于金融、泛安防等行业场景,满足身份核验、人脸考勤、闸机通行等业务需求",
"auto.k_ebe13d08": "机器翻译",
"auto.k_9e3042e2": "支持术语定制功能,用户可对翻译结果进行干预,快速提高翻译质量。",
"auto.k_5bea967e": "定制功能",
"auto.k_752bbb7b": "云与业务安全",
"auto.k_7c548e20": "密钥管理服务",
"auto.k_d9a10d6e": "用户可以按需创建自己的主密钥,并使用主密钥产生、加密和解密数据密钥。",
"auto.k_734a3f18": "密钥管理",
"auto.k_96c41446": "主机安全",
"auto.k_69493a93": "面向企业客户推出的云服务器安全防护产品。",
"auto.k_3e40e91b": "海量经验,病毒查杀",
"auto.k_aea16be7": "云防火墙",
"auto.k_a672ab23": "自定义防护策略,有效保护用户源站安全。",
"auto.k_cf6d5913": "自定义防护",
"auto.k_9415928": "应用防火墙",
"auto.k_5933138d": "可拦截SQL注入、XSS、文件上传等黑客攻击并自定义防护策略",
"auto.k_7d354326": "高危漏洞防护",
"auto.k_61a625d7": "入侵检测系统",
"auto.k_9e5421e4": "云堡垒机",
"auto.k_189c9a71": "帮助企业实现生产服务器等IT环境的安全运维。",
"auto.k_598ccbff": "安全运维",
"auto.k_affca802": "DDoS防护服务",
"auto.k_a2375f74": "能够全面防护各种网络层和应用层的DDoS攻击。",
"auto.k_106ec8a4": "全面防护",
"auto.k_27ff77f3": "业务安全风控系统",
"auto.k_84ddf22e": "提供多维度业务风控服务,打造反黑产、反羊毛党等反作弊能力",
"auto.k_161a9453": "反作弊",
"auto.k_63b358d5": "边缘计算",
"auto.k_71d117bc": "边缘计算节点",
"auto.k_d92ba6f6": "一站式地提供靠近终端用户的弹性计算资源。",
"auto.k_dbe551dc": "弹性计算",
"auto.k_72244a06": "云原生平台",
"auto.k_e5bab477": "商标知产服务",
"auto.k_d2c29f9a": "专业服务助力规避风险 | 智能商标注册限时特惠",
"auto.k_3584db55": "知识产权",
"auto.k_61317c38": "容器引擎",
"auto.k_104149bd": "助力系统架构微服务化、DevOps运维、AI应用深度学习容器化等场景。",
"auto.k_45024589": "容器化,微服务",
"auto.k_f080b461": "工商财税服务",
"auto.k_87fdacd8": "工商财税一站式服务,企业顾问一对一,助您省心省力开公司",
"auto.k_ab7dbe91": "工商财税",
"auto.k_cbf52e56": "智能内容科技",
"auto.k_64bdf283": "媒体内容分析",
"auto.k_7b724627": "对视频和图片进行结构化分析,输出内容的泛标签,帮助平台实现个性化内容推荐",
"auto.k_14a94485": "个性化",
"auto.k_d4f36be9": "智慧城市",
"auto.k_85c28bd7": "舆情服务",
"auto.k_f8d6a93d": "为政企用户提供事件定位、脉络还原、处置研判辅助决策,助力客户全方位掌握系统性舆论风险",
"auto.k_42e9d7": "舆情",
"auto.k_a2a31a94": "SME企业服务",
"auto.k_bc6cfe59": "SSL证书",
"auto.k_a3fc5d82": "BaiduTrust超级SSL证书拥有多年签发、免部署、访问加速、搜索加权等优势权益",
"auto.k_dd5895b2": "智能门户",
"auto.k_f097392b": "独家享有多项百度搜索优势权益。",
"auto.k_f9a42196": "百度搜索",
"auto.k_f071b753": "视频云平台",
"auto.k_9f1adb46": "容器镜像服务",
"auto.k_3b399598": "与容器引擎CCE等服务无缝集成助力企业提升云原生容器应用交付效率。",
"auto.k_59ab505": "百余款域名后缀随心选,注册任意域名即赠免费百度官方建站应用",
"auto.k_dd492beb": "智能短信",
"auto.k_df497eec": "简单消息服务",
"auto.k_bc6452c6": "适用于验证码、通知、营销等多种场景,帮助企业快速获取用户、构建服务闭环。",
"auto.k_7528": "用",
"auto.k_8f9acd0": "AI应用",
"auto.k_d4f12c45": "智慧医疗",
"auto.k_47b0bfd2": "灵医智能体",
"auto.k_d4f56a70": "智慧客服",
"auto.k_f408eb81": "客悦·智能客服",
"auto.k_a92e329a": "返回算力市场",
"auto.k_352eddc": "计费方式:",
"auto.k_daf7aae1": "计费规则",
"auto.k_7c28eb07": "创建完主机后仍然可以转换计费方式。如选择按量计费,价格发生变动以实例开机时的价格为准",
"auto.k_aa27f4e7": "选择主机:",
"auto.k_96951162": "主机ID",
"auto.k_ea56e1": "算力型号/显存",
"auto.k_fe16d0e4": "空闲GPU",
"auto.k_94c8b040": "每GPU分配",
"auto.k_a31259b8": "CPU型号",
"auto.k_3e161c": "硬盘",
"auto.k_e5a8dbbb": "驱动/CUDA",
"auto.k_c64270f2": "价格(单卡)",
"auto.k_643828c3": "GPU数量:",
"auto.k_2284ccee": "数据盘: 免费50GB",
"auto.k_5ffabcfd": "需要扩容",
"auto.k_220c3f9": "实例规格:",
"auto.k_2745ae63": "镜像:",
"auto.k_4291145b": "没有我要的环境?",
"auto.k_22e55078": "基础镜像包含常用基本软件深度学习框架、Miniconda等。如需其他软件可创建后安装",
"auto.k_133624f8": "请选择框架名称/框架版本/Python版本/CUDA版本",
"auto.k_b2b2364a": "优惠券:",
"auto.k_24f0a833": "请选择",
"auto.k_91a3f213": "新人专享满100减10元",
"auto.k_c35ea6c8": "充值满500减50元",
"auto.k_664081f9": "VIP用户满1000减100元",
"auto.k_b128381d": "日常费用: ¥0.00/日",
"auto.k_b43f4db": "费用明细",
"auto.k_362d4a34": "账户余额 ¥0.00",
"auto.k_e1af0e94": "余额不足去充值",
"auto.k_2b540a": "取消",
"auto.k_b0e3ed6": "资源筛选",
"auto.k_c873be5e": "组合筛选条件,快速定位合适算力规格",
"auto.k_ab0ae497": "重置筛选",
"auto.k_5b04603f": "轻量应用服务器 Simple Application Server是可快速搭建且易于管理的轻量级云服务器提供基于单台服务器的应用部署安全管理运维监控等服务一站式提升您的服务器使用体验和效率。",
"auto.k_325715": "快速启动",
"auto.k_ee44bed0": "30秒一键启动您的应用",
"auto.k_4afc0673": "持续提供多样的应用功能,帮助您便捷地管理、配置、分析应用",
"auto.k_7d7b12f1": "灵活的镜像选择",
"auto.k_1dc10570": "轻量应用服务器提供应用镜像和系统镜像可选总计21款满足您的不同应用需求。",
"auto.k_cb4e1ce7": "应用镜像",
"auto.k_e599994b": "提供WordPress、LAMP、Docker和Node.js等选择减少了应用的上传、安装等环节实现应用的开箱即用。",
"auto.k_7acbbb23": "个人建站应用、专属空间",
"auto.k_26d9a8e6": "知识效率管理,工具垂手可得",
"auto.k_125a8015": "选择精品镜像创建个人网站,企业官网",
"auto.k_8d312c1": "支持的系统镜像",
"auto.k_8a354dce": "立即咨询",
"auto.k_289436": "产品",
"auto.k_46e788": "规格",
"auto.k_a67785a6": "计算方式:",
"auto.k_2ae297": "包月",
"auto.k_2ada03": "包年",
"auto.k_ac772764": "选择地区:",
"auto.k_c2320676": "随机可用区",
"auto.k_370086d7": "北京二区",
"auto.k_baecb079": "新昌A区",
"auto.k_f469434a": "杭州A区",
"auto.k_d22bec33": "深圳A区",
"auto.k_9eda5fe4": "国产算力:",
"auto.k_13deb0b8": "(可短租)",
"auto.k_2ac85a": "功能",
"auto.k_2d091d": "场景",
"auto.k_284e38": "个人",
"auto.k_f5601a4f": "扫码添加官方客服",
"auto.k_74a58c8e": "提交咨询",
"auto.k_5853242f": "需求描述",
"auto.k_cdbe77bb": "请输入您的具体需求",
"auto.k_61431881": "客户类型",
"auto.k_71ad3b1d": "联系人姓名",
"auto.k_82ce5ab4": "请输入联系人姓名",
"auto.k_71b1a3b2": "联系人手机",
"auto.k_82d2c349": "请输入联系人手机",
"auto.k_ff2f20b3": "公司名称",
"auto.k_68d77110": "请输入公司名称",
"auto.k_71c974d2": "联系人邮箱",
"auto.k_82ea9469": "请输入联系人邮箱",
"auto.k_93c8f976": "勾选表示:您同意",
"auto.k_9177df70": "及其授权的合作伙伴通过您填写的联系方式联系您,且数据仅用于与您沟通。当您注销平台账号后,您的数据会被销毁。",
"auto.k_15f4726e": "取 消",
"auto.k_1a235154": "提 交",
"auto.k_380c44": "注册",
"auto.k_3d0046": "登录",
"auto.k_63cc4f1b": "当前位置:",
"auto.k_35a13a": "查看",
"auto.k_645a22e8": "网站地图/Site map",
"auto.k_a94ced38": "经营性网站备案信息",
"auto.k_bde6eceb": "点击查询备案号",
"auto.k_a06c662e": "产品服务",
"auto.k_52fb8a4e": "联系我们",
"auto.k_1702458a": "地址:",
"auto.k_2622eacb": "邮箱:",
"auto.k_1ef98f0e": "电话:",
"auto.k_e7374136": "微信客服",
"auto.k_66a72d63": "关注公众号",
"auto.k_79db82ad": "版权所有 @kaiyuanyun 2023",
"auto.k_3227713d": "经营许可证:京B2-20232313",
"auto.k_e4c2b952": "服务中心",
"auto.k_c7c24dde": "新闻资讯",
"auto.k_febb523e": "关于我们",
"auto.k_5f338c14": "产品名称4090",
"auto.k_71baf8df": "整合活体检测、人脸比对、身份证OCR等功能直连公安权威数据源 提供APP、H5、云服务等整套集成及运维方案有效拦截人脸信息伪造、设备攻击等黑产行为保障业务运转。",
"auto.k_3e19749d": "2*万兆网口100Gb/s高速网卡",
"auto.k_1b7caeea": "标签1",
"auto.k_93af09b6": "一个平台,千行百业",
"auto.k_dd54984d": "智能跃迁",
"auto.k_1c6ca72e": "AI+解决方案",
"auto.k_39b260aa": "成功案例",
"auto.k_7ce3cdb3": "想了解这些方案如何落地",
"auto.k_42486b03": "获取行业专属 AI 解决方案",
"auto.k_c00a78b0": "联系我们 →",
"auto.k_aab35b7e": "企业动态",
"auto.k_bb7c1af2": "查看更多 →",
"auto.k_c27a8a4f": "好用还省钱Token 就上开元云",
"auto.k_72b75396": "公共服务平台",
"auto.k_e6acb5f5": "汇聚海量精品模型,以更低成本畅享极致 AI 体验",
"auto.k_8a32a1f9": "立即体验",
"auto.k_27c68d0e": "创镜工坊",
"auto.k_4537b357": "以文筑境,以镜生画,全场景 AI 影像创作",
"auto.k_a9ea2313": "了解更多",
"auto.k_9c3e78d3": "深耕基础云服务,筑牢 AI 平台数字根基",
"auto.k_cd74d141": "精品模型",
"auto.k_1132219e": "服务可用性",
"auto.k_aac50534": "企业用户",
"auto.k_e5e4cfc2": "低至0.001",
"auto.k_f1221458": "每千Token起步价",
"auto.k_86134e4d": "您还没有完善企业信息,完善企业信息审核通过后您可以发布需求与商品。",
"auto.k_25754cff": "跳转到",
"auto.k_cd88a94a": "信息完善",
"auto.k_eb46f365": "温馨提示",
"auto.k_32a537": "我的",
"auto.k_2a1ac1": "关注",
"auto.k_3c9751e": "管理您关注的企业商品和需求",
"auto.k_aab4a718": "企业商品",
"auto.k_aad660c7": "企业需求",
"auto.k_baeeec74": "暂无关注记录",
"auto.k_a1eddfe1": "${month}月${day}日",
"auto.k_6f67cfbd": "${targetYear}年${month}月${day}日",
"auto.k_28aa87": "今天",
"auto.k_349fa1": "昨天",
"auto.k_2a7690": "前天",
"auto.k_a74524f2": "${diffDays}天前",
"auto.k_4160fbc6": "${weeks}周前",
"auto.k_31b4332c": "${months}个月前",
"auto.k_bd006e6b": "${years}年前",
"auto.k_387935": "浏览",
"auto.k_47da65": "记录",
"auto.k_fad13012": "查看您的商品和需求浏览历史",
"auto.k_7e289a88": "暂无浏览记录",
"auto.k_15549c58": "关 闭",
"auto.k_b2a6b283": "数智开物",
"auto.k_492a27ef": "热门推荐",
"auto.k_c79c4402": "加载中...",
"auto.k_5a32928e": "企业名称:",
"auto.k_15876aef": "内存:",
"auto.k_e0aece92": "系统盘:",
"auto.k_b1e63470": "数据盘:",
"auto.k_218157b6": "网卡:",
"auto.k_50087452": "商品描述:",
"auto.k_536b7c75": "相关参数:",
"auto.k_f8bec61d": "应用场景:",
"auto.k_18cdf3f3": "已收藏",
"auto.k_247766b8": "所属类别:",
"auto.k_ecccd5e8": "更新日期:",
"auto.k_5717a506": "未通过原因:",
"auto.k_94053235": "预览图片",
"auto.k_68d873d6": "裁剪图片",
"auto.k_662f": "是",
"auto.k_5426": "否",
"auto.k_837ffdcc": "商品价格",
"auto.k_8aed99a4": "预期价格",
"auto.k_2836c0fa": "预览图",
"auto.k_42b89b2a": "所属类别",
"auto.k_aab42c1c": "企业名称",
"auto.k_145c7c79": "请输入企业名称",
"auto.k_ff43a938": "公司类别",
"auto.k_21dac21f": "联系人",
"auto.k_41f985": "职务",
"auto.k_34574d3a": "请输入职务",
"auto.k_46f550d9": "手机号码",
"auto.k_b09da136": "请输入手机号码",
"auto.k_4a84bb": "邮箱",
"auto.k_ed30e0c0": "请输入邮箱地址",
"auto.k_e9503cf2": "GPU支持",
"auto.k_b44d40bf": "请输入CPU规格",
"auto.k_2a1267": "内存",
"auto.k_6e3ad284": "请输入内存规格",
"auto.k_fa841a03": "请输入GPU规格",
"auto.k_20fb78c8": "系统盘",
"auto.k_adb9e27": "请输入系统盘规格",
"auto.k_1ac33912": "数据盘",
"auto.k_1a34bec1": "请输入数据盘规格",
"auto.k_4179d4": "网卡",
"auto.k_8f1efc59": "请输入网卡规格",
"auto.k_28d0a1": "价格",
"auto.k_867ade4d": "支持 JPG、PNG 格式,最大 5MB",
"auto.k_336214": "提交",
"auto.k_4b1b55": "重置",
"auto.k_47f5228b": "确认裁剪",
"auto.k_2a43c6": "关闭",
"auto.k_8384236c": "商品图片",
"auto.k_c64df876": "图片裁剪",
"auto.k_c656409d": "图片预览",
"auto.k_5a33916e": "企业名称:",
"auto.k_4a7fde7e": "商品价格:",
"auto.k_17969e06": "预期价格:",
"auto.k_24786598": "所属类别:",
"auto.k_64b56d7d": "企业类别:",
"auto.k_52f254f7": "联系人:",
"auto.k_4f895e25": "手机号码:",
"auto.k_21c3ae29": "职务:",
"auto.k_fa9835f6": "发布日期:",
"auto.k_99d8b33b": "配置数据",
"auto.k_67fd7e9": "相关参数",
"auto.k_33b776": "搜索",
"auto.k_2bf793": "商品",
"auto.k_4db142": "需求",
"auto.k_e54e3309": "搜你想搜...",
"auto.k_295351": "供需",
"auto.k_30b237": "广场",
"auto.k_3a5f2f": "热门",
"auto.k_424a5fcc": "AI 行业应用领域,开元云为您提供完善的产品服务",
"auto.k_ab86def2": "暂无匹配的需求信息",
"auto.k_18837bab": "打破信息壁垒,助力降本增效",
"auto.k_30c7d0c7": "发布需求,精准匹配,与行业伙伴共建云服务生态",
"auto.k_541664e8": "发布需求",
"auto.k_5855557f": "需求标题",
"auto.k_52fd7969": "联系方式",
"auto.k_74c75ff6": "提交需求",
"auto.k_85311a0a": "搜索产品...",
"auto.k_d738ab54": "暂无数据",
"auto.k_1189154d": "请选择所属类别",
"auto.k_d59dcad7": "请描述应用场景,如:智能客服、金融风控、医疗影像等",
"auto.k_c1fda5dc": "请输入需求标题",
"auto.k_c044dbba": "请详细描述您的需求,包括场景、规模、期望交付方式等",
"auto.k_ad55e119": "手机号或邮箱",
"auto.k_2f820a2b": "客悦ONE·智能客服",
"auto.k_808ebef8": "智能整合全域沟通路径,精准响应用户需求,实现全旅程服务效能提升。",
"auto.k_ac2ddc78": "自助解决率",
"auto.k_ac9aa2b9": "首字时延",
"auto.k_bf4a273c": "时刻在线",
"auto.k_afcf61c4": "全链路用户服务接待",
"auto.k_fe188949": "在线机器人",
"auto.k_a0376a5": "免费体验",
"auto.k_cf1b89e2": "在线客服",
"auto.k_536f6162": "联络中心",
"auto.k_cc0ac7bd": "坐席辅助",
"auto.k_b49f92b": "多样化产品方案满足个性化需求",
"auto.k_3ff654ca": "SaaS部署",
"auto.k_2b6eda08": "按需购买、开箱即用的公有云软件",
"auto.k_aeb7ac7f": "满足不同规模企业的营销、服务需求",
"auto.k_ea3dfa7e": "本地部署",
"auto.k_b29c24b3": "支持不上云、不出域,可实现局域网极速传输",
"auto.k_ee00f23e": "全栈国产化信创适配,支持软硬一体机,合规无忧",
"auto.k_d57ff6f7": "开放平台",
"auto.k_1deb1ba9": "开放的API接口满足复杂业务场景",
"auto.k_bf08053a": "与企业官网、APP、CRM、OA等多种系统对接",
"auto.k_39df1a": "灵医",
"auto.k_1b17d914": "智能体",
"auto.k_8e1675a": "持续丰富能⼒ 赋能合作伙伴⽣产⼒升级",
"auto.k_5867ab46": "秒接DeepSeek立即体验",
"auto.k_2c77c8b5": "智能体医疗行业综合解决方案",
"auto.k_67cb5d9f": "诊前就医助手",
"auto.k_ded5e6af": "健康管家",
"auto.k_31730c52": "报告解读与生成",
"auto.k_d49699d7": "医学视觉溯源",
"auto.k_61c17c32": "识别各类医学影像图片,自动圈出病灶清晰边际",
"auto.k_9f4d84fd": "精准识别各类医学影像/可视化边界参考/辅助诊断",
"auto.k_8f9d9457": "中医舌诊/面诊",
"auto.k_26f505f7": "AI中医助手支持舌象面部分析",
"auto.k_42421d1c": "拓展中医新场景 / 提供日常调理建议 / 提供药物调理建议",
"auto.k_ded503f7": "健康科普",
"auto.k_d16cb8ea": "权威医学知识,有问必答",
"auto.k_1215e93": "深入理解内容 / 检索权威医学知识 / 大模型生成答案 /结果证据溯源",
"auto.k_8863e66c": "医学报告解读",
"auto.k_5dd248f7": "多类型多格式,高精准解读",
"auto.k_85c391cf": "解读准确度高 / 解读范围覆盖多类型报告",
"auto.k_b2f352d8": "药品咨询",
"auto.k_43bc0bf6": "海量药品说明书,答疑解难",
"auto.k_a7f1b764": "海量药品说明书 / 药品维度覆盖全面 / 大模型一对一问答",
"auto.k_9c250921": "皮肤病咨询",
"auto.k_3b1964a6": "覆盖百余种皮肤病,大模型生成诊断建议",
"auto.k_22f6d914": "全身皮肤拍照检测 / 皮肤类疾病可涵盖95%以上 / 皮肤图片医学解读",
"auto.k_15aa11f4": "分导诊",
"auto.k_b25ac853": "精准推荐就诊科室,科室百分百覆盖",
"auto.k_afcd4037": "多轮对话收集患者主诉 / 科室推荐准确率超95% / 大模型人机对话",
"auto.k_283d2d38": "预问诊",
"auto.k_a5e6221e": "多轮问诊生成病历病历生成可用率超95%",
"auto.k_63d17817": "多轮对话收集患者主诉 / 病历生成可用率超95% / 大模型人机对话",
"auto.k_c6754278": "医疗知识库问答",
"auto.k_b8c235d8": "海量数据资源,问答准确率业内领先",
"auto.k_e1caab02": "检索文档数量上限超1万 / 医学问答准确率业内领先 / 兼容不同格式",
"auto.k_362db66d": "临床辅助决策",
"auto.k_7c688629": "根据病情推荐诊断诊断准确率超90%",
"auto.k_337155c7": "推荐内容有据可循 / 诊断覆盖全面 / 对话模式一问一答",
"auto.k_e66edb6b": "症状自诊",
"auto.k_134c1ad3": "病情自查自测,实时就医指导",
"auto.k_362199d0": "遵循医学诊疗规范 / 病情自查自测 / 实时就医指导 /健康问题覆盖全面",
"auto.k_eb95efe5": "AI模型全流程开发",
"auto.k_d278f148": "开始使用",
"auto.k_e12e47cc": "访问平台",
"auto.k_b19ec9a0": "全链路AI开发能力",
"auto.k_89fe0d8d": "覆盖从数据处理到模型部署的全流程一站式解决AI开发需求",
"auto.k_19822ae1": "一站式开发流程",
"auto.k_68236277": "从想法到产品上线,全流程无缝衔接",
"auto.k_208c3db": "预计时间:",
"auto.k_8a1881": "告别部署烦恼",
"auto.k_8794934d": "登录/注册",
"auto.k_af7cfce": "资源信息",
"auto.k_a21fa305": "资源描述:",
"auto.k_2b75ed8a": "供电方式:",
"auto.k_267fed08": "供电功率:",
"auto.k_11e65c52": "机柜高度:",
"auto.k_c4d3d3bb": "可租数量:",
"auto.k_b0d93aac": "计算资源:",
"auto.k_f6531a01": "网络架构:",
"auto.k_47a4d84": "计费模式:",
"auto.k_ca80787e": "可租算力:",
"auto.k_56c64dae": "试用场景:",
"auto.k_ba1e3e13": "试用1场景:",
"auto.k_30ce450f": "交易地址:",
"auto.k_541b360e": "信息过期时间:",
"auto.k_52f15617": "联系人:",
"auto.k_124c904e": "产品单价:",
"auto.k_9d88781a": "登录后查看",
"auto.k_3cf92dee": "需求说明:",
"auto.k_71aa1959": "联系人员:",
"auto.k_77b520f5": "联系方式:",
"auto.k_331ee0b2": "需求时间:",
"auto.k_404e5419": "需求预算:",
"auto.k_46674ba": "版权所有 © 2023开元云北京科技有限公司",
"auto.k_cc18530c": "供给信息",
"auto.k_5848c1e4": "需求信息",
"auto.k_b49e100": "查看更多",
"auto.k_34fc9f": "智谱",
"auto.k_dfd2620b": "讯飞星火",
"auto.k_2b3137": "千问",
"auto.k_83d7e8fa": "豆包大模型",
"auto.k_b3f0ee98": "文心一言",
"auto.k_66c24902": "浪潮千业大模型"
}

View File

@ -0,0 +1,97 @@
import autoMessages from './zh-CN.auto.json'
export default {
common: {
language: '语言',
chinese: '中文',
english: 'English'
},
topbar: {
home: '首页',
product: '产品',
cases: '案例',
news: '动态',
login: '登录',
registerNow: '立即注册',
console: '控制台',
switchZhSuccess: '已切换为中文',
switchEnSuccess: '已切换为英文'
},
home: {
heroTitle: '一个平台,千行百业',
heroSubtitle: '智能跃迁',
heroSlogan: '让AI无处不在让智能如此简单',
solutionsBtn: '解决方案',
contactSalesBtn: '联系销售',
aiSolutionsTitle: 'AI+解决方案',
successCasesTitle: '成功案例',
moreCases: '更多案例',
ctaTitle: '想了解这些方案如何落地?',
ctaDesc: '获取行业专属 AI 解决方案',
contactUsArrow: '联系我们',
companyNewsTitle: '企业动态',
viewMore: '查看更多 →',
footerProducts: '产品服务',
footerContact: '联系我们',
onlineChat: '在线咨询',
solutionCards: {
collaboration: {
title: '群智协作',
subtitle: '多智能体协同'
},
spatial: {
title: '空间觉醒',
subtitle: 'GIS智能分析'
},
predictive: {
title: '先见一步',
subtitle: '智能预测引擎'
},
vision: {
title: '洞察入微',
subtitle: '机器视觉检测'
},
qa: {
title: '一问即达',
subtitle: '智能问答知识库'
},
protection: {
title: '全程守护',
subtitle: '设备智能监控'
},
document: {
title: '触文即懂',
subtitle: '智能文档解析'
},
edge: {
title: '端侧即算',
subtitle: '边缘AI推理'
}
},
cases: {
railway: {
name: '中国中铁 · 慧投标智能体',
title: '智慧工程',
desc: 'AI驱动投标全流程从标书解读到报价编制中标率提升显著'
},
forestry: {
name: '南宁林业局',
title: '智慧采伐',
desc: '从采伐审批到科学监管——空间智能融合,让数据真正服务林区治理。'
},
beigang: {
name: '北港大数据',
title: 'AI赋能数智升级',
desc: '从投标到决策从合同到管理——全链路AI智能体让业务快人一步'
}
},
news: {
tag: '企业动态',
firstTitle: '开元云随贸促会走访东盟',
firstDesc: '开元云科技随贸促会广西分会经贸代表团密集出访越南、老挝,深度参与区域 AI 产业合作与数字经济交流。',
secondTitle: '开元云荣登福布斯中国人工智能商业落地示范企业',
secondDesc: '凭借 AI 智能体工厂的工业级交付能力与央国企标杆案例,开元云入选福布斯中国人工智能商业落地示范企业。'
}
},
...autoMessages
}

View File

@ -3,7 +3,7 @@ import Vue from 'vue'
import Cookies from 'js-cookie'
import 'normalize.css/normalize.css' // a modern alternative to CSS resets
import './assets/css/iconfont/iconfont.css'
import '@/assets/css/iconfont/iconfont.css'
import Element from 'element-ui'
import './styles/element-variables.scss'
@ -51,6 +51,7 @@ let ploady={
import App from './App'
import store from './store'
import router from './router'
import i18n from './i18n'
// import 'default-passive-events'
import './icons' // icon
import './permission' // permission control
@ -288,6 +289,11 @@ var onOverflow = ["/shoppingManagement", "/supplierManagement"];
// 修复:在路由守卫中恢复用户状态和重新生成路由
router.beforeEach(async (to, from, next) => {
if (to.path === '/login' || to.path.startsWith('/login/')) {
next();
return;
}
// 清空面包屑状态的代码
// store.commit('tagsView/resetBreadcrumbState');
@ -350,83 +356,12 @@ window.addEventListener('beforeunload', function () {
Object.keys(filters).forEach(key => {
Vue.filter(key, filters[key])
})
// 在 main.js 的 router.beforeEach 中添加
router.beforeEach((to, from, next) => {
// 清空面包屑状态的代码
// store.commit('tagsView/resetBreadcrumbState');
// 新增:检测是否为移动设备
// const userAgent = navigator.userAgent;
// const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
// // 如果是移动设备且访问的是根路径,重定向到移动端首页
// if (isMobile && to.path === '/') {
// next('/h5HomePage');
// return;
// }
// // 如果是移动设备且访问的不是移动端页面,重定向到移动端首页
// if (isMobile && !to.meta?.isMobile && to.path !== '/h5HomePage' && !to.path.startsWith('/h5HomePage/')) {
// next('/h5HomePage');
// return;
// }
// 如果已登录且有token但Vuex状态丢失从sessionStorage恢复
if (store.getters.token && (!store.getters.user || !store.getters.userType)) {
console.log("检测到状态丢失从sessionStorage恢复用户状态");
const user = sessionStorage.getItem('user');
const auths = sessionStorage.getItem('auths');
const userType = sessionStorage.getItem('userType');
const orgType = sessionStorage.getItem('orgType');
if (user) {
store.commit('user/SET_USER', user);
}
if (auths) {
store.commit('user/SET_AUTHS', JSON.parse(auths));
}
if (userType) {
store.commit('user/SET_USER_TYPE', userType);
}
if (orgType) {
store.commit('user/SET_ORG_TYPE', parseInt(orgType));
}
// 重新生成路由
try {
const accessRoutes = store.dispatch('permission/generateRoutes', {
user: store.getters.user,
auths: store.getters.auths,
userType: store.getters.userType,
orgType: store.getters.orgType
});
// 重新添加路由
router.addRoutes(accessRoutes);
// 重定向到当前路由以确保路由更新
next({ ...to, replace: true });
return;
} catch (error) {
console.error('重新生成路由失败:', error);
}
}
onOverflow.forEach(element => {
if (to.path == element) {
document.querySelector("body").setAttribute("style", "overflow: auto !important;")
}
});
next();
});
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
store,
i18n,
render: h => h(App)
})

View File

@ -65,7 +65,13 @@ export const constantRoutes = [
{
path: "/tokenMarket",
name: "PublicTokenMarket",
component: () => import('@/views/product/allProduct/index.vue'),
redirect: to => ({
path: "/homePage/tokenMarket",
query: {
category: to.query.category || "TOKEN市集",
single: to.query.single || "1",
}
}),
hidden: true,
meta: {
title: "TOKEN市集",
@ -153,6 +159,14 @@ export const constantRoutes = [
title: "智能客服详情", fullPath: "/h5HomePage/service",
},
},
{
path: "consultDialogFull",
title: '全屏咨询弹窗预览',
component: () => import('@/views/H5/consultDialogFullPreview/index.vue'),
meta: {
title: "全屏咨询弹窗预览", fullPath: "/h5HomePage/consultDialogFull",
},
},
]
},
{
@ -165,6 +179,7 @@ export const constantRoutes = [
title: "H5关于我们", fullPath: "/h5about/index",
},
},
{
path: '/beforeLogin',
name: 'BeforeLogin',
@ -337,6 +352,12 @@ export const constantRoutes = [
name: "homePageIndex",
hidden: true,
meta: { title: "首页", onCache: true },
}, {
path: "opc",
component: () => import("@/views/homePage/mainPage/OPC/index.vue"),
name: "homePageOPC",
hidden: true,
meta: { title: "OPC公共服务平台", onCache: true },
}, {
path: "computeMarket",
component: () => import("@/views/homePage/computeMarket/index.vue"),
@ -355,6 +376,12 @@ export const constantRoutes = [
name: "trainPlatform",
hidden: true,
meta: { title: "训推平台", onCache: true },
}, {
path: "tokenMarket",
component: () => import("@/views/product/allProduct/index.vue"),
name: "homePageTokenMarket",
hidden: true,
meta: { title: "TOKEN市集", onCache: true },
}, {
path: "agentStore",
component: () => import("@/views/homePage/agentStore"),
@ -380,6 +407,13 @@ export const constantRoutes = [
hidden: true,
meta: { title: "详情", onCache: true },
},
{
path: "news",
component: () => import("@/views/homePage/news/newsView.vue"),
name: "homePageNews",
hidden: true,
meta: { title: "企业动态", onCache: true },
},
{
path: "new",
component: () => import("@/views/homePage/components/topBox/new/index.vue"),
@ -775,6 +809,13 @@ export const asyncRoutes = [
hidden: true,
meta: { title: "首页", fullPath: "/homePage/index" },
},
{
path: "opc",
component: () => import("@/views/homePage/mainPage/OPC/index.vue"),
name: "homePageOPC",
hidden: true,
meta: { title: "OPC公共服务平台", fullPath: "/homePage/opc" },
},
{
path: "detail",
component: () => import("@/views/homePage/detail/index.vue"),

View File

@ -0,0 +1,586 @@
<template>
<el-dialog
:visible.sync="dialogVisible"
:fullscreen="true"
custom-class="mobile-consult-fullscreen-dialog"
:append-to-body="true"
:close-on-click-modal="false"
:close-on-press-escape="!submitSuccess"
:show-close="false"
@close="handleClose"
>
<div v-if="submitSuccess" class="submit-success-page">
<div class="success-icon">
<i class="el-icon-check"></i>
</div>
<h2 class="success-title">已完成</h2>
<p class="success-desc">您的咨询信息已提交我们会尽快与您联系</p>
</div>
<div v-else class="mobile-consult-wrap">
<h2 class="mobile-consult-title">{{ title }}</h2>
<p class="mobile-consult-subtitle">期待与您开启AI创新未来</p>
<el-form
ref="consultForm"
:model="formData"
:rules="rules"
label-position="top"
class="mobile-consult-form"
>
<el-form-item label="1. 请填写您的姓名" prop="name">
<el-input
v-model.trim="formData.name"
maxlength="20"
placeholder="请输入您的姓名"
/>
</el-form-item>
<el-form-item label="2. 请填写您的联系方式" prop="phone">
<el-input
v-model.trim="formData.phone"
maxlength="11"
placeholder="请输入您的联系电话"
/>
</el-form-item>
<el-form-item label="3. 请填写您的邮箱" prop="email">
<el-input
v-model.trim="formData.email"
maxlength="60"
placeholder="请输入您的邮箱"
/>
</el-form-item>
<el-form-item label="4. 请填写您的公司名称" prop="company">
<el-input
v-model.trim="formData.company"
maxlength="80"
placeholder="请输入您的公司名称"
/>
</el-form-item>
<el-form-item label="5. 请选择您的企业类型(单选)" prop="enterprise_type">
<el-radio-group v-model="formData.enterprise_type" class="option-grid">
<el-radio
v-for="item in enterpriseOptions"
:key="item.id"
:label="item.id"
class="option-item"
>
{{ item.name }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="6. 请选择您所在的省份(单选)" prop="region">
<el-select
v-model="formData.region"
filterable
placeholder="输入省份名称或拼音首字母搜索..."
class="full-select"
>
<el-option
v-for="item in provinceOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="7. 您想咨询的方向(可多选)">
<el-checkbox-group v-model="formData.consult_direction_list" class="direction-list">
<el-checkbox
v-for="item in consultDirectionOptions"
:key="item.id"
:label="item.id"
class="direction-item"
>
<span class="direction-main">{{ item.title }}</span>
<span class="direction-sub">{{ item.desc }}</span>
</el-checkbox>
</el-checkbox-group>
</el-form-item>
<el-form-item label="8. 如果您有其他问题需要咨询,请留言">
<el-input
v-model.trim="formData.content"
type="textarea"
:autosize="{ minRows: 3, maxRows: 5 }"
maxlength="500"
show-word-limit
placeholder="请输入您想咨询的内容..."
/>
</el-form-item>
</el-form>
<div class="qrcode-area">
<p>长按二维码添加微信获取专属服务</p>
<img src="@/assets/image/newkefu.png" alt="官方客服二维码">
</div>
<el-checkbox v-model="formData.checked" class="privacy-checkbox">
<span>
您填写的信息仅用于本次业务对接沟通公司将严格落实信息安全保护机制不泄露不滥用您的任何个人资料
</span>
</el-checkbox>
<el-button
type="primary"
class="submit-btn"
:loading="loading"
@click="handleSubmit"
>
提交咨询
</el-button>
</div>
</el-dialog>
</template>
<script>
import { reqConsultForm, reqProductConsult } from '@/api/H5'
export default {
name: 'MobileFullScreenConsultDialog',
props: {
visible: {
type: Boolean,
default: false
},
title: {
type: String,
default: '开元云科技合作咨询'
},
qrCode: {
type: String,
default: ''
},
currentUrl: {
type: String,
default: ''
},
submitApi: {
type: Function,
default: null
}
},
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 {
loading: false,
formData: this.getInitialFormData(),
enterpriseOptions: [],
provinceOptions: [],
consultDirectionOptions: [],
submitSuccess: false,
rules: {
name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
phone: [{ required: true, validator: validatePhone, trigger: 'blur' }],
email: [
{ required: true, message: '请输入邮箱', trigger: 'blur' },
{ type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur' }
],
company: [{ required: true, message: '请输入公司名称', trigger: 'blur' }],
enterprise_type: [{ required: true, message: '请选择企业类型', trigger: 'change' }],
region: [{ required: true, message: '请选择所在省份', trigger: 'change' }]
},
originalOverflow: ''
}
},
computed: {
dialogVisible: {
get() {
return this.visible
},
set(value) {
this.$emit('update:visible', value)
}
}
},
watch: {
visible: {
immediate: true,
handler(newVal) {
if (newVal) {
this.resetForm()
this.fetchConsultOptions()
this.disableBodyScroll()
} else {
this.enableBodyScroll()
}
}
}
},
methods: {
getInitialFormData() {
return {
custom_type: '1',
name: '',
phone: '',
email: '',
company: '',
enterprise_type: '',
region: '',
consult_direction_list: [],
content: '',
checked: false
}
},
resetForm() {
this.formData = this.getInitialFormData()
this.submitSuccess = false
this.$nextTick(() => {
if (this.$refs.consultForm) this.$refs.consultForm.clearValidate()
})
},
disableBodyScroll() {
this.originalOverflow = document.body.style.overflow
document.body.style.overflow = 'hidden'
},
enableBodyScroll() {
document.body.style.overflow = this.originalOverflow || ''
},
handleClose() {
this.dialogVisible = false
this.$emit('close')
},
normalizeDictOptions(list, type) {
return list
.filter(item => item && item.dict_type === type)
.sort((a, b) => Number(a.sort_order || 0) - Number(b.sort_order || 0))
.map(item => ({
id: item.dict_key,
name: item.dict_value
}))
},
normalizeDirectionOptions(list) {
return list
.filter(item => item && item.dict_type === 'direction')
.sort((a, b) => Number(a.sort_order || 0) - Number(b.sort_order || 0))
.map(item => {
const value = item.dict_value || ''
const match = value.match(/^(.+?)(.+?)$/)
return {
id: String(item.dict_key),
name: value,
title: match ? match[1] : value,
desc: match ? match[2] : ''
}
})
},
extractConsultOptionList(res) {
if (res && Array.isArray(res.data)) return res.data
if (res && res.data && Array.isArray(res.data.data)) return res.data.data
return []
},
async fetchConsultOptions() {
try {
const res = await reqConsultForm()
const list = this.extractConsultOptionList(res)
if (!list.length) return
const enterpriseOptions = this.normalizeDictOptions(list, 'enterprise_type')
const provinceOptions = this.normalizeDictOptions(list, 'region')
const consultDirectionOptions = this.normalizeDirectionOptions(list)
if (enterpriseOptions.length) this.enterpriseOptions = enterpriseOptions
if (provinceOptions.length) this.provinceOptions = provinceOptions
if (consultDirectionOptions.length) this.consultDirectionOptions = consultDirectionOptions
} catch (error) {
//
}
},
buildSubmitPayload() {
return {
custom_type: this.formData.custom_type,
name: this.formData.name,
phone: this.formData.phone,
email: this.formData.email,
company: this.formData.company,
enterprise_type: this.formData.enterprise_type,
region: this.formData.region,
consult_direction: this.formData.consult_direction_list.join(','),
content: this.formData.content,
source: '公众号',
url_link: this.currentUrl || window.location.href
}
},
async handleSubmit() {
if (!this.formData.checked) {
this.$message.warning('请先勾选信息安全与隐私保护说明')
return
}
this.$refs.consultForm.validate(async valid => {
if (!valid) return
this.loading = true
try {
const payload = this.buildSubmitPayload()
const response = this.submitApi ? await this.submitApi(payload) : await reqProductConsult(payload)
if (response && (response.status === true || response.status === 'true')) {
this.$emit('success', response)
this.submitSuccess = true
} else {
this.$message.error((response && response.msg) || '提交失败,请稍后再试')
}
} catch (error) {
this.$message.error('提交失败,请稍后再试')
} finally {
this.loading = false
}
})
}
},
beforeDestroy() {
this.enableBodyScroll()
}
}
</script>
<style scoped lang="less">
::v-deep .mobile-consult-fullscreen-dialog {
margin: 0 !important;
width: 100% !important;
max-width: 100% !important;
height: 100vh;
border-radius: 0;
.el-dialog__header {
padding: 14px 14px 8px;
border-bottom: 0;
}
.el-dialog__title {
font-size: 18px;
font-weight: 700;
color: #111827;
}
.el-dialog__body {
height: calc(100vh - 60px);
padding: 12px 14px 18px;
overflow-y: auto;
}
}
.mobile-consult-wrap {
padding-bottom: 8px;
}
.submit-success-page {
min-height: calc(100vh - 110px);
padding: 80px 24px 24px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
box-sizing: border-box;
}
.success-icon {
width: 88px;
height: 88px;
border-radius: 50%;
background: #22c55e;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 14px 28px rgba(34, 197, 94, 0.22);
i {
font-size: 46px;
font-weight: 700;
}
}
.success-title {
margin: 24px 0 10px;
color: #111827;
font-size: 24px;
font-weight: 700;
}
.mobile-consult-title {
margin: 0;
font-size: 24px;
line-height: 1.25;
color: #111827;
}
.mobile-consult-subtitle {
margin: 6px 0 16px;
font-size: 12px;
color: #9ca3af;
}
.mobile-consult-form {
::v-deep .el-form-item {
margin-bottom: 18px;
}
::v-deep .el-form-item__content,
::v-deep .el-input,
::v-deep .el-select,
::v-deep .el-textarea {
width: 100%;
}
::v-deep .el-form-item__label {
padding-bottom: 6px;
font-size: 13px;
line-height: 1.3;
color: #1f2937;
font-weight: 600;
}
::v-deep .el-form-item__error {
position: static;
padding-top: 6px;
line-height: 1.25;
font-size: 12px;
}
::v-deep .el-input__inner {
height: 40px;
border-radius: 10px;
border: 1px solid #e5e7eb;
}
::v-deep .el-form-item.is-error .el-input__inner,
::v-deep .el-form-item.is-error .el-textarea__inner {
border-color: #f56c6c;
}
::v-deep .el-textarea__inner {
border-radius: 10px;
border: 1px solid #e5e7eb;
}
}
.option-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 8px;
width: 100%;
}
.option-item {
margin-right: 0 !important;
padding: 9px 8px;
border: 1px solid #e5e7eb;
border-radius: 10px;
white-space: nowrap;
box-sizing: border-box;
display: flex;
align-items: center;
width: 100%;
::v-deep .el-radio__label {
padding-left: 6px;
font-size: 12px;
color: #374151;
}
}
.full-select {
width: 100%;
}
.direction-list {
display: flex;
flex-direction: column;
gap: 8px;
width: 100%;
}
.direction-item {
margin-right: 0 !important;
border: 1px solid #e5e7eb;
border-radius: 10px;
padding: 10px;
display: flex;
align-items: flex-start;
width: 100%;
box-sizing: border-box;
::v-deep .el-checkbox__label {
display: inline-flex;
flex-direction: column;
gap: 2px;
padding-left: 8px;
}
}
.direction-main {
font-size: 14px;
color: #111827;
line-height: 1.2;
}
.direction-sub {
font-size: 12px;
color: #9ca3af;
line-height: 1.2;
}
.qrcode-area {
margin: 16px 0;
text-align: center;
padding: 18px 0;
background: #f7f8fa;
border-radius: 12px;
p {
margin: 0 0 10px;
font-size: 12px;
color: #6b7280;
}
img {
width: 98px;
height: 98px;
border-radius: 8px;
border: 1px dashed #3b82f6;
}
}
.privacy-checkbox {
margin: 0 0 14px;
display: flex;
align-items: flex-start;
::v-deep .el-checkbox__input {
margin-top: 3px;
}
::v-deep .el-checkbox__label {
padding-left: 8px;
color: #6b7280;
font-size: 12px;
line-height: 1.6;
white-space: normal;
}
}
.submit-btn {
width: 100%;
height: 44px;
border: none;
border-radius: 999px;
background: #111827;
color: #fff;
font-size: 16px;
font-weight: 600;
}
</style>

View File

@ -1,3 +1,4 @@
<!-- 产品咨询弹窗公众号 -->
<template>
<el-dialog
:title="title"

View File

@ -0,0 +1,43 @@
<template>
<div class="consult-full-preview">
<div class="preview-actions">
<el-button type="primary" @click="dialogVisible = true">打开全屏咨询弹窗</el-button>
</div>
<mobile-full-screen-consult-dialog
:visible.sync="dialogVisible"
:current-url="currentUrl"
/>
</div>
</template>
<script>
import MobileFullScreenConsultDialog from '../components/H5_dialog/MobileFullScreenConsultDialog.vue'
export default {
name: 'ConsultDialogFullPreview',
components: { MobileFullScreenConsultDialog },
data() {
return {
dialogVisible: true
}
},
computed: {
currentUrl() {
return window.location.href
}
}
}
</script>
<style scoped lang="less">
.consult-full-preview {
min-height: 100%;
}
.preview-actions {
padding: 12px;
display: flex;
justify-content: center;
}
</style>

View File

@ -1,5 +1,5 @@
<template>
<div style="width: 100%;">
<div class="about-page" style="width: 100%;">
<!-- Banner部分 -->
<div class="banner">
<div v-if="JSON.stringify(logoInfoNew) !== '{}'" style="font-size: 38px;">

View File

@ -73,13 +73,13 @@
.hero-section {
position: relative;
z-index: 1;
padding: 80px 24px;
padding: 162px 24px 80px;
overflow: hidden;
text-align: center;
}
.hero-section--compact {
padding: 80px 24px;
padding: 162px 24px 80px;
}
.hero-content {
@ -240,6 +240,7 @@
position: relative;
display: flex;
overflow: hidden;
min-height: 320px;
padding: 32px;
background: #fff;
border-radius: 24px;
@ -270,6 +271,7 @@
display: flex;
flex: 1;
flex-direction: column;
min-height: 0;
}
.app-card__header {
@ -303,6 +305,7 @@
color: #4b5563;
font-size: 16px;
line-height: 1.625;
flex: 1;
}
.tag-list {
@ -310,6 +313,7 @@
flex-wrap: wrap;
align-items: center;
gap: 8px;
margin-top: auto;
}
.feature-tag {
@ -489,7 +493,7 @@
@media (max-width: 760px) {
.hero-section,
.hero-section--compact {
padding: 48px 18px;
padding: 120px 18px 48px;
}
.hero-title {

View File

@ -117,9 +117,9 @@ export default {
{ id: 'internet', label: '互联网' }
],
apps: [
{ id: 1, name: 'E招标', description: '全流程电子化招标交易核心工具支持多品类招标业务线上开展实现招投标全过程无纸化运行。搭载多CA互认、在线清标、电子保函等实用功能保障招标合规高效。', tags: ['多CA互认', '在线清标', '电子保函'], category: 'general', subCategory: 'bidding', iconPath: 'M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z', decorClass: 'decor-gradient-blue', iconClass: 'icon-gradient-blue' },
{ id: 2, name: 'E投标', description: '适配全品类电子招投标场景的线上投标工具,支持在线完成信息注册、标书获取、文件编制、加密提交全流程操作。实时同步招标变更与澄清信息,保障投标过程安全可追溯。', tags: ['在线签章', '加密提交', '变更同步'], category: 'general', subCategory: 'bidding', iconPath: 'M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12', decorClass: 'decor-gradient-green', iconClass: 'icon-gradient-green', externalUrl: 'https://bid-ocai-v2.jinan.opencomputing.cn/' },
{ id: 3, name: 'E评标', description: '智能化线上评审系统,覆盖专家签到、清标比对、符合性评审、打分汇总、报告生成全流程。支持标书交叉比对、废标在线操作与澄清收发,提升评标效率与规范性。', tags: ['专家云签', '交叉比对', '智能打分'], category: 'general', subCategory: 'bidding', iconPath: 'M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4', decorClass: 'decor-gradient-indigo', iconClass: 'icon-gradient-indigo' },
{ id: 1, name: 'E招标', description: 'E招标智能体AI辅助编制招标文件自动合规性审查让招标流程更高效、更透明、更合规。', tags: ['多CA互认', '在线清标', '电子保函'], category: 'general', subCategory: 'bidding', iconPath: 'M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z', decorClass: 'decor-gradient-blue', iconClass: 'icon-gradient-blue' },
{ id: 2, name: 'E投标', description: 'E投标智能体是覆盖「招标解析→标书编制→合规审查→查重→知识沉淀」全链路的一站式投标AI解决方案帮企业将编标周期从数天压缩至小时级低级废标率降低100%。', tags: ['在线签章', '加密提交', '变更同步'], category: 'general', subCategory: 'bidding', iconPath: 'M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12', decorClass: 'decor-gradient-green', iconClass: 'icon-gradient-green', externalUrl: 'https://bid-ocai-v2.jinan.opencomputing.cn/' },
{ id: 3, name: 'E评标', description: 'E评标智能体AI辅助评标分析自动提取关键指标、横向对比评分、识别异常报价帮助评标专家高效、公正地完成评审工作。', tags: ['专家云签', '交叉比对', '智能打分'], category: 'general', subCategory: 'bidding', iconPath: 'M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4', decorClass: 'decor-gradient-indigo', iconClass: 'icon-gradient-indigo' },
{ id: 4, name: '合同智能审查', description: 'AI驱动的办公智能体可快速识别合同中的风险条款、表述歧义、合规漏洞自动标注问题位置并给出修改建议。支持多类型合同模板适配大幅缩短人工审查时长。', tags: ['风险识别', '批量审查', '审查报告'], category: 'general', subCategory: 'office', iconPath: 'M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z', decorClass: 'decor-gradient-amber', iconClass: 'icon-gradient-amber', casePath: '/homePage/agentStore/contractCase' },
{ id: 5, name: '投策智能体', description: '面向企业投资决策的辅助智能体,整合多维度市场数据、行业趋势与政策信息,通过算法模拟不同决策场景的收益与风险,自动生成可视化分析报告,提升投资方案科学性。', tags: ['场景模拟', '可视化报告', '风险预判'], category: 'general', subCategory: 'office', iconPath: 'M13 7h8m0 0v8m0-8l-8 8-4-4-6 6', decorClass: 'decor-gradient-purple', iconClass: 'icon-gradient-purple', casePath: '/homePage/agentStore/decisionCase' },
{ id: 6, name: '采伐智审', description: '面向林业管理的行业智能体,可在线完成采伐申请材料的智能核验,自动比对采伐范围、树种、蓄积量等核心指标与合规要求,快速识别违规申请,助力林业资源可持续利用。', tags: ['智能核验', '合规比对', '违规识别'], category: 'industry', subCategory: 'forestry', iconPath: 'M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L22 12l-6.714 3.143L13 22l-2.286-6.857L4 12l6.714-3.143L13 2z', decorClass: 'decor-gradient-emerald', iconClass: 'icon-gradient-emerald' },
@ -168,5 +168,9 @@ export default {
</script>
<style scoped>
.agent-store-page {
padding-top: 0;
}
@import './agent.css';
</style>

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
<template>
<div>
<div class="news-page">
new
</div>

View File

@ -1,5 +1,5 @@
<template>
<div>sale</div>
<div class="sale-page">sale</div>
</template>
<script lang="ts">
import Vue from 'vue'

View File

@ -424,7 +424,7 @@ export default {
<style scoped lang="scss">
.compute-market-page {
min-height: 100vh;
padding: 28px 0 8px;
padding: 82px 0 8px;
background:
radial-gradient(circle at top left, rgba(64, 158, 255, 0.18), transparent 34%),
radial-gradient(circle at top right, rgba(14, 165, 233, 0.12), transparent 28%),

View File

@ -1,5 +1,5 @@
<template>
<div style="width: 100%;">
<div class="detail-page" style="width: 100%;">
<!-- 顶部容器设置最小宽度和flex布局 -->
<div id="topContainer"
style="min-width: 1400px; width: 100%;display: flex;flex-direction: column;justify-content: flex-start;align-items: center">

View File

@ -1,48 +1,85 @@
<template>
<div>
<el-dialog
title="产品咨询"
:visible.sync="showTalk"
width="1000px"
title="联系销售"
:visible="dialogVisible"
width="400px"
center
append-to-body
:close-on-click-modal="false"
@close="cancelBtn"
top="15px"
@update:visible="handleDialogVisibleUpdate"
top="8vh"
custom-class="talk-dialog"
>
<el-form ref="ruleForm" :rules="rules" label-position="top" label-width="80px" :model="addData">
<el-form-item label="需求描述">
<el-input :autosize="{ minRows: 3, maxRows: 3}" type="textarea" size="mini"
v-model="addData.content"></el-input>
</el-form-item>
<el-form-item label="客户类型">
<el-radio v-model="addData.custom_type" label="1">企业</el-radio>
<el-radio v-model="addData.custom_type" label="0">个人</el-radio>
</el-form-item>
<el-form-item style="margin-bottom: 10px" label="联系人姓名" prop="name">
<el-input style="width: 350px;" size="mini" v-model="addData.name"></el-input>
</el-form-item>
<el-form-item style="margin-bottom: 10px" prop="phone" label="联系人手机">
<el-input style="width: 350px;" size="mini" v-model="addData.phone"></el-input>
</el-form-item>
<el-form-item v-show="addData.custom_type==='1'" style="margin-bottom: 10px" label="公司名称">
<el-input style="width: 350px;" size="mini" v-model="addData.company"></el-input>
</el-form-item>
<el-form-item style="margin-bottom: 10px" label="联系人邮箱">
<el-input style="width: 350px;" size="mini" v-model="addData.email"></el-input>
</el-form-item>
</el-form>
<el-checkbox style="margin-top: 25px" v-model="checked">
勾选表示您同意<span v-if="JSON.stringify(logoInfoNew)!=='{}'">{{ logoInfoNew.home.bannerTitle }}</span>及其授权的合作伙伴通过您填写的联系方式联系您且数据仅用于与您沟通当您注销平台账号后您的数据会被销毁
</el-checkbox>
<div class="qcode">
<img v-if="JSON.stringify(logoInfoNew)!=='{}'" :src="logoInfoNew.home.qrCode" alt="">
<span style="margin-top: 10px;display: inline-block">扫码添加官方客服</span>
<div class="talk-body">
<div class="talk-form">
<el-form ref="ruleForm" :rules="rules" label-position="top" label-width="80px" :model="addData">
<div class="form-grid">
<el-form-item label="1. 请填写您的姓名" prop="name">
<el-input v-model.trim="addData.name" maxlength="20" placeholder="请输入您的姓名"></el-input>
</el-form-item>
<el-form-item prop="phone" label="2. 请填写您的联系方式">
<el-input v-model.trim="addData.phone" maxlength="11" placeholder="请输入您的联系电话"></el-input>
</el-form-item>
<el-form-item label="3. 请填写您的邮箱" prop="email" class="form-item--compact">
<el-input v-model.trim="addData.email" maxlength="60" placeholder="请输入您的邮箱"></el-input>
</el-form-item>
<el-form-item label="4. 请填写您的公司名称" prop="company" class="form-item--compact">
<el-input v-model.trim="addData.company" maxlength="80" placeholder="请输入您的公司名称"></el-input>
</el-form-item>
<el-form-item label="5. 请选择您的企业类型(单选)" prop="enterprise_type" class="form-item--full">
<el-radio-group v-model="addData.enterprise_type" class="option-grid">
<el-radio
v-for="item in enterpriseOptions"
:key="item.id"
:label="item.id"
class="option-item"
>
{{ item.name }}
</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="6. 请选择您所在的省份(单选)" prop="region" class="form-item--full">
<el-select
v-model="addData.region"
filterable
placeholder="输入省份名称或拼音首字母搜索..."
class="full-select"
>
<el-option
v-for="item in provinceOptions"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item label="7. 如果您有其他问题需要咨询,请留言" class="form-item--message">
<el-input
v-model.trim="addData.content"
type="textarea"
:autosize="{ minRows: 3, maxRows: 5 }"
maxlength="500"
show-word-limit
placeholder="请输入您想咨询的内容..."
></el-input>
</el-form-item>
</div>
</el-form>
<el-checkbox class="agreement-checkbox" v-model="checked">
您填写的信息仅用于本次业务对接沟通公司将严格落实信息安全保护机制不泄露不滥用您的任何个人资料
</el-checkbox>
</div>
<div v-if="qrCodeUrl" class="qcode">
<img :src="qrCodeUrl" alt="官方客服二维码">
<span>扫码添加官方客服</span>
</div>
</div>
<span slot="footer" class="dialog-footer">
<!-- <el-button size="mini" @click="cancelBtn"> </el-button>-->
<el-button size="mini" type="primary" @click="confirmBtn"> </el-button>
</span>
<el-button class="cancel-btn" @click="cancelBtn">取消</el-button>
<el-button class="submit-btn" type="primary" :loading="addBtnLoading" @click="confirmBtn">提交咨询</el-button>
</span>
</el-dialog>
</div>
</template>
@ -50,27 +87,48 @@
import Vue from 'vue'
import {mapState} from "vuex";
import {reqNewHomeConsult} from "@/api/newHome";
import {reqConsultForm} from "@/api/H5";
export default Vue.extend({
name: "talk",
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 {
rules: {
name: [
{required: true, message: '请输入姓名', trigger: 'blur'},
],
phone: [
{required: true, message: '请输入手机号', trigger: 'change'},
{
pattern: /^1[3-9]\d{9}$/,
message: '请输入正确的手机号码',
trigger: 'blur'
}
{required: true, validator: validatePhone, trigger: 'blur'}
],
email: [
{required: true, message: '请输入邮箱', trigger: 'blur'},
{type: 'email', message: '请输入正确的邮箱地址', trigger: 'blur'}
],
company: [
{required: true, message: '请输入公司名称', trigger: 'blur'}
],
enterprise_type: [
{required: true, message: '请选择企业类型', trigger: 'change'}
],
region: [
{required: true, message: '请选择所在省份', trigger: 'change'}
]
},
addBtnLoading: false,
checked: false,
dialogVisible: false,
enterpriseOptions: [],
provinceOptions: [],
addData: {
content: '',//
custom_type: "1",// 0- 1-
@ -78,6 +136,8 @@ export default Vue.extend({
phone: "",//
company: "",//
email: "",//
enterprise_type: '',
region: '',
},
labelPosition: 'right',
formLabelAlign: {
@ -87,10 +147,68 @@ export default Vue.extend({
}
}
},
watch: {
showTalk: {
immediate: true,
handler(value) {
this.dialogVisible = value
if (value) {
this.fetchConsultOptions()
}
}
}
},
methods: {
getDefaultFormData() {
return {
content: '',
custom_type: '1',
name: '',
phone: '',
company: '',
email: '',
enterprise_type: '',
region: '',
}
},
normalizeDictOptions(list, type) {
return list
.filter(item => item && item.dict_type === type)
.sort((a, b) => Number(a.sort_order || 0) - Number(b.sort_order || 0))
.map(item => ({
id: item.dict_key,
name: item.dict_value
}))
},
extractConsultOptionList(res) {
if (res && Array.isArray(res.data)) return res.data
if (res && res.data && Array.isArray(res.data.data)) return res.data.data
return []
},
async fetchConsultOptions() {
try {
const res = await reqConsultForm()
const list = this.extractConsultOptionList(res)
if (!list.length) return
const enterpriseOptions = this.normalizeDictOptions(list, 'enterprise_type')
const provinceOptions = this.normalizeDictOptions(list, 'region')
if (enterpriseOptions.length) this.enterpriseOptions = enterpriseOptions
if (provinceOptions.length) this.provinceOptions = provinceOptions
} catch (error) {
//
}
},
handleDialogVisibleUpdate(value) {
this.dialogVisible = value;
if (!value) {
this.$store.commit('setShowTalk', false);
}
},
cancelBtn() {
this.dialogVisible = false;
this.$store.commit('setShowTalk', false);
console.log("取消按钮被点击了");
},
confirmBtn() {
if (!this.checked) {
@ -100,8 +218,12 @@ export default Vue.extend({
this.$refs['ruleForm'].validate((valid) => {
if (valid) {
this.addBtnLoading = true
this.addData.url_link = window.location.href
reqNewHomeConsult(this.addData).then(response => {
const submitData = {
...this.addData,
source: '官网',
url_link: window.location.href
}
reqNewHomeConsult(submitData).then(response => {
this.addBtnLoading = false
if (response.status) {
this.$message({
@ -109,14 +231,8 @@ export default Vue.extend({
message: '感谢您关注人工智能服务平台,我们将尽快联系您!~'
});
this.$store.commit('setShowTalk', false);
this.addData = {
content: '',
custom_type: "1",
name: "",
phone: "",
company: "",
email: "",
}
this.addData = this.getDefaultFormData()
this.checked = false
} else {
this.$message.error(response.msg || '提交失败,请稍后再试!');
}
@ -138,47 +254,274 @@ export default Vue.extend({
showTalk: (state) => state.product.showTalk,
logoInfoNew: state => state.product.logoInfoNew,
}),
qrCodeUrl() {
return this.logoInfoNew && this.logoInfoNew.home && this.logoInfoNew.home.qrCode
? this.logoInfoNew.home.qrCode
: ''
},
},
})
</script>
<style scoped lang="scss">
::v-deep .talk-dialog {
border-radius: 22px;
overflow: hidden;
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
// z-index: 99999999999999999!important;
width: 600px !important;
}
::v-deep .el-dialog__header {
display: flex;
justify-content: center;
align-items: center;
padding: 18px 22px 6px;
border: none;
}
::v-deep .el-dialog__title {
color: #111827;
font-size: 22px;
line-height: 1.4;
font-weight: 700;
}
::v-deep .el-dialog__headerbtn {
top: 26px;
right: 28px;
font-size: 20px;
}
::v-deep .el-dialog__body {
padding: 6px 24px 4px;
}
::v-deep .el-form-item__label {
padding-bottom: 0;
padding-bottom: 8px;
color: #374151;
font-size: 15px;
line-height: 1.4;
font-weight: 600;
}
::v-deep .el-form-item {
margin-bottom: 0;
margin-bottom: 18px;
}
::v-deep .el-form-item__error {
position: static;
padding-top: 6px;
line-height: 1.25;
font-size: 12px;
}
::v-deep .el-input__inner,
::v-deep .el-textarea__inner {
border-radius: 12px;
border-color: #e5eaf3;
color: #111827;
font-size: 15px;
pointer-events: auto;
user-select: text;
}
::v-deep .el-input__inner {
height: 42px;
line-height: 42px;
}
::v-deep .el-textarea__inner {
padding: 12px 14px;
line-height: 1.7;
}
::v-deep .el-radio__label {
color: #374151;
font-size: 15px;
}
.talk-body {
position: relative;
min-height: 430px;
padding-bottom: 8px;
display: block;
}
.talk-form {
width: 100%;
min-width: 0;
padding-right: 0;
}
::v-deep .talk-form .el-form-item__content,
::v-deep .talk-form .el-input,
::v-deep .talk-form .el-select,
::v-deep .talk-form .el-textarea {
width: 100%;
}
.form-grid {
display: block;
}
.form-item--compact {
width: 100%;
}
.form-item--full {
width: 100%;
}
.form-item--message {
width: calc(100% - 184px);
}
.full-select {
width: 100%;
}
.option-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 8px;
width: 100%;
}
.option-item {
margin-right: 0 !important;
padding: 9px 8px;
border: 1px solid #e5eaf3;
border-radius: 12px;
white-space: nowrap;
box-sizing: border-box;
width: 100%;
::v-deep .el-radio__label {
padding-left: 6px;
color: #374151;
font-size: 13px;
}
}
.agreement-checkbox {
margin-top: 8px;
max-width: calc(100% - 184px);
display: inline-flex;
align-items: flex-start;
::v-deep .el-checkbox__label {
color: #6b7280;
font-size: 13px;
line-height: 1.7;
white-space: normal;
}
::v-deep .el-checkbox__input {
margin-top: 4px;
}
}
.qcode {
width: 150px;
height: 150px;
min-height: 162px;
padding: 12px 10px;
position: absolute;
right: 150px;
bottom: 150px;
right: 0;
bottom: 18px;
border-radius: 18px;
background: linear-gradient(180deg, #f4f8ff 0%, #ffffff 100%);
border: 1px solid #edf1f7;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
box-sizing: border-box;
img {
width: 100%;
height: 100%;
width: 104px;
height: 104px;
object-fit: cover;
border-radius: 12px;
}
span {
margin-top: 10px;
color: #4b5563;
font-size: 13px;
font-weight: 600;
}
}
::v-deep .el-dialog__footer {
display: flex;
justify-content: flex-start;
justify-content: center;
align-items: center;
padding-top: 0;
padding-bottom: 35px;
gap: 14px;
padding: 6px 22px 22px;
}
.cancel-btn,
.submit-btn {
min-width: 150px;
height: 42px;
padding: 0 28px;
border-radius: 999px;
font-size: 15px;
font-weight: 600;
}
.cancel-btn {
border: 1px solid #d8e0ef;
color: #4b5563;
background: #fff;
}
.submit-btn {
border: 0;
background: linear-gradient(90deg, #275AFF 0%, #2EBDFA 100%);
box-shadow: 0 12px 28px rgba(39, 90, 255, 0.22);
}
@media (max-width: 900px) {
::v-deep .talk-dialog {
width: 92vw !important;
}
.talk-body {
min-height: auto;
display: block;
padding-right: 0;
padding-bottom: 8px;
}
.talk-form {
padding-right: 0;
}
.qcode {
position: static;
width: 100%;
min-height: auto;
margin-top: 20px;
}
.form-item--compact {
width: 100%;
}
.form-item--full {
width: 100%;
}
.form-item--message {
width: 100%;
}
.agreement-checkbox {
max-width: 100%;
}
}
</style>

View File

@ -2,96 +2,78 @@
<div id="homeOut" class="homeOut">
<TopBox id="topBox"></TopBox>
<router-view></router-view>
<div class="home-router-view">
<router-view></router-view>
</div>
<!-- footer-->
<div class="footer">
<div class="left-box" style="border-bottom: 1px solid #7A82A0">
<div class="footer-main">
<div class="footer-brand-col">
<img
v-if="hasLogoInfo"
:src="footerHomeInfo.logoImg"
alt="logo"
class="footer-brand-logo"
>
</div>
<div style="display: flex;flex-direction: column">
<img v-if="JSON.stringify(logoInfoNew)!=='{}'" style="width: 148px;height: 48px;"
:src="logoInfoNew.home.logoImg" alt=""
class="img">
<div class="content-main">
<ul class="info">
<li>地址<span v-if="JSON.stringify(logoInfoNew)!=='{}'">{{ logoInfoNew.home.adress }}</span>
</li>
<li v-if="JSON.stringify(logoInfoNew)!=='{}'"> 邮箱{{logoInfoNew.home.email}}</li>
<!-- <li v-if="JSON.stringify(logoInfoNew)!=='{}'">电话: <span class="tel">{{logoInfoNew.home.mobile}}</span> -->
<!-- </li> -->
<div class="footer-link-cols">
<li>
<!-- <a href="" rel="noreferrer" target="_blank"></a> -->
<div class="footer-link-col">
<h4 class="footer-col-title">{{ $t('home.footerProducts') }}</h4>
<ul class="footer-link-list">
<li
v-for="item in footerProductServices"
:key="item.label"
class="footer-link-item"
:class="{ clickable: !!item.path }"
@click="goFooterService(item.path)"
>
{{ item.label }}
</li>
</ul>
</div>
<div class="footer-contact-col">
<h4 class="footer-col-title">{{ $t('home.footerContact') }}</h4>
<ul class="footer-contact-list">
<li>地址<span>{{ footerHomeInfo.adress }}</span></li>
<li>邮箱<span>{{ footerHomeInfo.email }}</span></li>
<li>电话<span>{{ footerHomeInfo.mobile }}</span></li>
</ul>
<div v-if="showFooterQrcode" class="footer-qrcode-row">
<div class="qr-box">
<div class="qr-code">
<img src="./img/img.png" alt="">
</div>
<span class="qr-content">{{ $t('home.onlineChat') }}</span>
</div>
<div class="qr-box">
<div class="qr-code">
<img src="./img/kefu.jpg" alt="">
</div>
<span class="qr-content">关注公众号</span>
</div>
</div>
</div>
<ul class="bigUl">
<!-- <li class="bigLi">-->
<!-- <span class="title">关于我们</span>-->
<!-- <ul class="smallUl">-->
<!-- <li class="smallLi" @click="$router.push('/homePage/about')">公司介绍</li>-->
<!-- </ul>-->
<!-- <span class="title"> </span>-->
<!-- </li>-->
<!-- <li class="bigLi">-->
<!-- <span class="title">产品</span>-->
<!-- <ul class="smallUl">-->
<!-- <li @click="goBaidu" class="smallLi">百度云</li>-->
<!-- <li @click="goAliyun" class="smallLi">阿里云</li>-->
<!-- &lt;!&ndash; <li class="smallLi">开元云</li>&ndash;&gt;-->
<!-- </ul>-->
<!-- <span class="title"> </span>-->
<!-- </li>-->
<!-- <li class="bigLi">-->
<!-- <span class="title">解决方案</span>-->
<!-- <ul class="smallUl">-->
<!-- <li class="smallLi">生物医药</li>-->
<!-- </ul>-->
<!-- <span class="title"> </span>-->
<!-- </li>-->
<!-- <li class="bigLi">-->
<!-- <span class="title">服务与支持</span>-->
<!-- <ul class="smallUl">-->
<!-- <li class="smallLi">模型微调</li>-->
<!-- <li class="smallLi">模型应用</li>-->
<!-- <li class="smallLi">业务咨询</li>-->
<!-- <li class="smallLi">加入开元</li>-->
<!-- </ul>-->
<!-- <span class="title"> </span>-->
<!-- </li>-->
</ul>
<div v-if="JSON.stringify(logoInfoNew)!=='{}'&&logoInfoNew.home.bannerTitle!=='开元数智'" class="right-box">
<div class="qr-box">
<div class="qr-code">
<img src="./img/img.png" alt="">
</div>
<span class="qr-content">微信客服</span>
</div>
<div class="qr-box" style="margin-left: 0.667rem">
<div class="qr-code">
<img src="./img/kefu.jpg" style="padding: 0.08rem" alt="">
</div>
<span class="qr-content">关注公众号</span>
</div>
</div>
</div>
<div style="display: flex;justify-content: center;align-items: center;width: 100%; ">
<span v-if="JSON.stringify(logoInfoNew)!=='{}'"
style="margin:15px 0 ;width: 1400px;display:flex;justify-content:center;align-items:center;color: #7A82A0;"><span
<div class="footer-record">
<span v-if="hasLogoInfo"
class="footer-record__text"><span
class="goStyle"
@click="goOut('https://beian.miit.gov.cn/#/Integrated/index')">
京ICP备{{
logoInfoNew.home.license
footerHomeInfo.license
}}&nbsp;
<span style="padding: 4px;"></span>
</span> &nbsp;&nbsp;{{
logoInfoNew.home.footerTitle
footerHomeInfo.footerTitle
}}&nbsp;{{
logoInfoNew.home.copyright
footerHomeInfo.copyright
}}&nbsp; </span>
<!-- IPC备案号:{{ ICP }} <span style="margin-left: 0.267rem">版权所有 @kaiyuanyun 2023</span>-->
<!-- <img src="../../image/login/policeInsignia/policeInsignia.png" alt=""-->
@ -110,7 +92,6 @@
<script>
import Vue from 'vue'
import TopBox from "@/views/homePage/components/topBox/index.vue";
import {reqNewHomeFestival} from "@/api/newHome";
import {mapGetters, mapState} from "vuex";
export default Vue.extend({
@ -150,6 +131,39 @@ export default Vue.extend({
icon: require("./newImg/container.png"),
activeIcon: require("./newImg/containerActive.png")
}
],
footerProductServices: [
{ label: 'Token市集', path: '/homePage/tokenMarket' },
{ label: '算力市场', path: '/homePage/computeMarket' },
{ label: 'OPC公共服务平台', path: '/homePage/opc' },
{ label: '训推平台', path: '/homePage/trainPlatform' },
{ label: '智能体商店', path: '/homePage/agentStore' },
{ label: '供需广场', path: '/ncmatchHome/supplyAndDemandSquare' },
{ label: '文档中心', path: '/homePage/new' },
],
footerAboutUs: [
{ label: '关于我们', path: '/homePage/about' },
{ label: '文件中心', path: '/homePage/new' },
{ label: '联系我们', path: '/homePage/about' },
{ label: '人才招聘', path: '' },
{ label: '云作坊', path: '' },
{ label: '友情链接', path: '' },
],
footerSolutions: [
{ label: '汽车行业', path: '/homePage/solve/hospital' },
{ label: '金融行业', path: '' },
{ label: '政务行业', path: '' },
{ label: '工业行业', path: '' },
{ label: '教育行业', path: '' },
{ label: '医疗行业', path: '' },
{ label: '互联网行业', path: '' },
],
footerSupports: [
{ label: '备案服务', path: '' },
{ label: '服务咨询', path: '' },
{ label: '建议与反馈', path: '/homePage/about' },
{ label: '常见问题', path: '/homePage/new' },
{ label: '帮助中心', path: '/homePage/new' },
]
}
},
@ -170,6 +184,15 @@ export default Vue.extend({
console.log("此时是:", orgType !== '2' && orgType !== '3' && userId !== null)
return orgType !== '2' && orgType !== '3' && userId === null;
},
hasLogoInfo() {
return this.logoInfoNew && JSON.stringify(this.logoInfoNew) !== '{}' && this.logoInfoNew.home
},
footerHomeInfo() {
return this.hasLogoInfo ? this.logoInfoNew.home : {}
},
showFooterQrcode() {
return this.hasLogoInfo && this.footerHomeInfo.bannerTitle !== '开元数智'
},
username() {
return sessionStorage.getItem('username') || '';
},
@ -179,6 +202,10 @@ export default Vue.extend({
goOut(url){
window.open(url)
},
goFooterService(path) {
if (!path || this.$route.path === path) return
this.$router.push(path)
},
scrollToElement(id) {
const element = document.getElementById(id);
if (element) {
@ -247,121 +274,165 @@ export default Vue.extend({
height: 100%;
overflow: auto !important;
min-width: 1500px;
// background: linear-gradient(180deg, #f0f7ff 0%, #ffffff 60%, #f5f8ff 100%);
}
#topBox{
// height: 82px;
background: transparent!important;
background-color: transparent!important;
box-shadow: none!important;
border: 0!important;
}
.home-router-view {
width: 100%;
padding-top: 0;
box-sizing: border-box;
}
.footer {
padding: 35px 0;
padding: 38px 0 22px;
width: 100%;
display: flex;
justify-content: center;
flex-wrap: wrap;
background: #f1f3f7;
}
.left-box {
.footer-main {
width: 1400px;
height: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 15px;
align-items: flex-start;
gap: 38px;
padding: 0 0 32px;
border-bottom: 1px solid rgba(122, 130, 160, 0.22);
box-sizing: border-box;
}
.right-box {
height: 100%;
.footer-brand-col {
width: 150px;
padding-top: 2px;
}
.footer-brand-logo {
width: 180px;
height: 50px;
object-fit: contain;
object-position: left center;
}
.footer-link-cols {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
justify-content: flex-start;
align-items: flex-start;
gap: 60px;
}
.content-main {
mix-blend-mode: normal;
color: rgba(0, 0, 0, 1);
font-size: 0.187rem;
.footer-link-col {
min-width: 110px;
}
.qr-code {
img {
width: 100%;
height: 100%;
}
width: 1.853rem;
height: 1.853rem;
}
.qr-content {
mix-blend-mode: normal;
color: rgba(24, 24, 24, 1);
font-family: PingFang SC, serif;
.footer-col-title {
margin: 0 0 14px;
color: #202634;
font-size: 16px;
font-weight: 600;
font-size: 0.187rem;
line-height: 1.5;
}
.footer-link-list {
margin: 0;
padding: 0;
list-style: none;
}
.footer-link-item {
margin-bottom: 9px;
color: #5d6477;
font-size: 14px;
line-height: 1.5;
white-space: nowrap;
transition: color .2s ease, transform .2s ease;
}
.footer-link-item:last-child {
margin-bottom: 0;
}
.footer-link-item.clickable {
cursor: pointer;
}
.footer-link-item.clickable:hover {
color: #1b5bff;
transform: translateX(3px);
}
.footer-contact-list {
margin: 0;
padding: 0;
list-style: none;
color: #5d6477;
font-size: 14px;
line-height: 1.6;
li {
margin-bottom: 5px;
}
}
.footer-qrcode-row {
margin-top: 14px;
display: flex;
align-items: flex-start;
gap: 14px;
}
.qr-box {
display: flex;
justify-content: center;
flex-direction: column;
align-items: center;
}
.logo {
background-color: #32abfc;
.qr-code {
width: 120px;
height: 120px;
padding: 4px;
border: 1px solid #dde3ef;
background: #fff;
box-sizing: border-box;
img {
width: 100%;
height: 100%;
object-fit: cover;
}
}
.bigUl {
margin: 0 15px;
margin-left: -250px;
//padding-top: 15px;
width: fit-content;
.qr-content {
margin-top: 8px;
color: #5d6477;
font-size: 13px;
line-height: 1.4;
}
.footer-record {
width: 100%;
display: flex;
justify-content: flex-start;
.bigLi {
margin: 0 25px;
}
height: 100%;
.title {
color: #222F60;
font-size: 18px;
font-weight: bold;
}
.smallUl {
font-size: 16px;
color: #7A82A0;
li {
margin: 10px 0;
}
}
justify-content: center;
align-items: center;
}
.info {
font-size: 14px;
color: #7A82A0;
li {
margin: 10px 0;
}
}
.tel {
color: #222F60;
font-size: 20px;
}
.smallLi {
&:hover {
color: #1b5bff;
cursor: pointer;
}
.footer-record__text {
width: 1400px;
margin: 18px 0 0;
display: flex;
justify-content: center;
align-items: center;
color: #7a82a0;
font-size: 13px;
}
.goStyle {

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
<!-- <div class="search-box">
<search></search>
</div> -->
<div style="width: 100%;">
<div class="ncmatch-router-view">
<router-view></router-view>
</div>
@ -239,6 +239,12 @@ export default Vue.extend({
background-color: #f6f8fd;
}
.ncmatch-router-view {
width: 100%;
padding-top: 0;
box-sizing: border-box;
}
.footer {
padding: 35px 0;
width: 100%;

View File

@ -750,6 +750,7 @@ export default {
.plaza-page {
position: relative;
min-height: 100vh;
padding-top: 0;
overflow-x: hidden;
background: linear-gradient(180deg, #f0f7ff 0%, #ffffff 60%, #f5f8ff 100%);
color: #1a1a1a;
@ -805,7 +806,7 @@ export default {
position: relative;
z-index: 1;
overflow: hidden;
padding: 96px 24px 64px;
padding: 178px 24px 64px;
}
.hero-glow {

View File

@ -0,0 +1,236 @@
<template>
<div class="news-view-page">
<div class="orb orb-1"></div>
<div class="orb orb-2"></div>
<div class="orb orb-3"></div>
<section class="news-hero">
<div class="news-hero-glow news-hero-glow-1"></div>
<div class="news-hero-glow news-hero-glow-2"></div>
<div class="news-shell">
<div class="hero-content">
<span class="hero-badge">COMPANY NEWS</span>
<div class="hero-title-row">
<h1>企业动态</h1>
<button type="button" class="about-link" @click="goAbout">关于我们 </button>
</div>
<p>了解开元云最新动态把握AI行业前沿资讯与我们一起见证智能跃迁</p>
</div>
</div>
</section>
<section class="filter-section">
<div class="news-shell">
<div class="filter-tabs">
<button
v-for="item in filterTabs"
:key="item.value"
type="button"
class="filter-tab"
:class="{ active: activeCategory === item.value }"
@click="activeCategory = item.value"
>
{{ item.label }}
</button>
</div>
</div>
</section>
<section class="featured-section">
<div class="news-shell">
<article v-if="featuredNews" class="news-featured">
<div class="news-item-glow"></div>
<span class="hover-detail">详情 <i class="el-icon-arrow-right"></i></span>
<div class="news-featured-inner">
<div class="news-featured-img">
<img :src="featuredNews.img || fallbackNewsImage" :alt="featuredNews.title">
</div>
<div class="news-featured-body">
<div class="news-featured-date">
<span class="category-pill" :style="{ background: featuredNews.tagColor }">{{ featuredNews.tag }}</span>
{{ featuredNews.date }}
</div>
<h2>{{ featuredNews.title }}</h2>
<p>{{ featuredNews.desc }}</p>
</div>
</div>
</article>
</div>
</section>
<section class="news-list-section">
<div class="news-shell">
<div class="news-grid">
<article
v-for="(item, index) in filteredNewsList"
:key="item.id"
class="news-item"
:style="{ animationDelay: `${(index + 1) * 0.08}s` }"
>
<div class="news-item-glow"></div>
<span class="hover-detail">详情 <i class="el-icon-arrow-right"></i></span>
<div class="news-item-img">
<img :src="item.img || fallbackNewsImage" :alt="item.title">
<div class="news-item-img-overlay"></div>
<span class="news-item-tag" :style="{ background: item.tagColor }">{{ item.tag }}</span>
</div>
<div class="news-item-body">
<div class="news-item-date">{{ item.date }}</div>
<h3>{{ item.title }}</h3>
<p>{{ item.desc }}</p>
</div>
</article>
</div>
<div class="pagination">
<button type="button" class="pagination-btn"><i class="el-icon-arrow-left"></i></button>
<button type="button" class="pagination-btn active">1</button>
<button type="button" class="pagination-btn">2</button>
<button type="button" class="pagination-btn">3</button>
<button type="button" class="pagination-btn"><i class="el-icon-arrow-right"></i></button>
</div>
</div>
</section>
</div>
</template>
<script>
export default {
name: 'NewsView',
data() {
return {
fallbackNewsImage: require('@/assets/image/news.jpg'),
activeCategory: 'all',
filterTabs: [
{ label: '全部', value: 'all' },
{ label: '企业动态', value: 'company' },
{ label: '产品动态', value: 'product' },
{ label: '行业洞察', value: 'industry' },
{ label: '活动资讯', value: 'event' }
],
newsList: [
{
id: 0,
category: 'company',
tag: '企业动态',
tagColor: 'rgba(16,185,129,0.85)',
date: '2026.6.15',
title: '开元云随贸促会走访东盟',
desc: '开元云科技随贸促会广西分会经贸代表团密集出访越南、老挝,深度参与中国-东盟经贸合作以AI技术赋能区域产业升级推动智能体工厂落地东南亚市场。',
img: '',
featured: true,
content: '<p>开元云科技随贸促会广西分会经贸代表团密集出访越南、老挝,深度参与中国-东盟经贸合作。</p><p>在此次出访中开元云向东南亚市场全面展示了AI智能体工厂的工业级交付能力涵盖智慧工程、智能运维、能源管理等多个核心领域的技术方案。</p><p>此次东盟之行标志着开元云正式开启东南亚市场战略布局未来将持续深化与东盟各国在AI领域的合作以技术赋能区域产业升级。</p>'
},
{
id: 1,
category: 'company',
tag: '企业动态',
tagColor: 'rgba(16,185,129,0.85)',
date: '2026.05.17',
title: '开元云荣登福布斯中国人工智能商业落地示范企业',
desc: '凭借AI智能体工厂的工业级交付能力与央国企标杆案例开元云入选福布斯中国人工智能商业落地示范企业成为行业AI落地标杆。',
content: '<p>凭借AI智能体工厂的工业级交付能力与央国企标杆案例开元云入选福布斯中国人工智能商业落地示范企业。</p><p>此次评选从技术实力、商业落地、行业影响力等多维度综合评估,开元云凭借智能体工厂产品创新力成功跻身示范企业榜单。</p>'
},
{
id: 2,
category: 'product',
tag: '产品动态',
tagColor: 'rgba(99,102,241,0.85)',
date: '2026.05.10',
title: '智能体工厂2.0正式发布全面升级AI交付能力',
desc: '开元云智能体工厂2.0版本重磅上线新增多智能体协同编排、可视化工作流设计等核心功能AI应用交付效率提升300%。',
content: '<p>开元云智能体工厂2.0版本重磅上线,新增多智能体协同编排、可视化工作流设计等核心功能。</p><p>2.0版本支持复杂业务场景的智能体协作、拖拽式工作流构建和增强的文档智能处理能力。</p>'
},
{
id: 3,
category: 'industry',
tag: '行业洞察',
tagColor: 'rgba(13,148,136,0.85)',
date: '2026.04.28',
title: '2026年AI+能源行业趋势:从预测性维护到智能调度',
desc: 'AI技术正在重塑能源行业从发电设备的预测性维护到电网智能调度开元云深度解析行业变革趋势与落地实践。',
content: '<p>AI技术正在重塑能源行业从发电设备的预测性维护到电网智能调度行业正在进入智能化深水区。</p><p>基于机器视觉和传感器数据融合的预测性维护方案已在火电、风电领域广泛应用。</p>'
},
{
id: 4,
category: 'event',
tag: '活动资讯',
tagColor: 'rgba(245,158,11,0.85)',
date: '2026.04.15',
title: '开元云亮相2026中国人工智能大会',
desc: '开元云受邀出席2026中国人工智能大会现场展示智能体工厂最新技术成果与行业领袖共话AI产业化新路径。',
content: '<p>开元云受邀出席2026中国人工智能大会现场展示智能体工厂最新技术成果。</p><p>在大会主论坛上开元云系统阐述了AI技术从实验创新到工业级交付的方法论。</p>'
},
{
id: 5,
category: 'company',
tag: '企业动态',
tagColor: 'rgba(16,185,129,0.85)',
date: '2026.03.22',
title: '开元云与南宁林业局达成智慧林业战略合作',
desc: '开元云携手南宁林业局打造林业空间采伐智审系统融合GIS空间分析、卫星遥感等多源数据审批周期从数天压缩至分钟级。',
img: '',
content: '<p>开元云携手南宁林业局打造林业空间采伐智审系统融合GIS空间分析、卫星遥感等多源数据。</p><p>项目上线后,采伐审批效率显著提升,成为智慧林业标杆案例。</p>'
},
{
id: 6,
category: 'product',
tag: '产品动态',
tagColor: 'rgba(236,72,153,0.85)',
date: '2026.03.08',
title: '机器视觉检测平台升级,支持工业质检全场景覆盖',
desc: '开元云机器视觉检测平台全面升级,新增缺陷分类、尺寸测量、表面检测三大能力模块,覆盖制造业全场景质检需求。',
content: '<p>开元云机器视觉检测平台全面升级,新增缺陷分类、尺寸测量、表面检测三大能力模块。</p><p>该平台已在汽车零部件、3C电子、半导体封装等行业完成部署。</p>'
},
{
id: 7,
category: 'industry',
tag: '行业洞察',
tagColor: 'rgba(37,99,235,0.85)',
date: '2026.02.20',
title: 'AI+教育:大模型如何重构个性化学习路径',
desc: '从知识图谱构建到学习路径智能推荐大模型正在从根本上改变教育模式。开元云分享AI+教育的最新落地实践与思考。',
content: '<p>从知识图谱构建到学习路径智能推荐,大模型正在从根本上改变教育模式。</p><p>基于大模型的自适应学习系统可以实时评估学习者知识掌握程度,动态调整学习路径。</p>'
},
{
id: 8,
category: 'event',
tag: '活动资讯',
tagColor: 'rgba(124,58,237,0.85)',
date: '2026.02.05',
title: '开元云荣获2025年度AI创新企业TOP50',
desc: '在2025年度人工智能创新企业评选中开元云凭借卓越的技术创新能力和丰富的行业落地经验成功入选AI创新企业TOP50。',
content: '<p>在2025年度人工智能创新企业评选中开元云凭借卓越的技术创新能力和丰富的行业落地经验成功入选。</p>'
},
{
id: 9,
category: 'company',
tag: '企业动态',
tagColor: 'rgba(234,88,12,0.85)',
date: '2026.01.18',
title: '开元云完成B轮融资加速AI智能体产业布局',
desc: '开元云科技宣布完成B轮融资融资金额将用于加速AI智能体工厂产品研发、行业解决方案深化及海外市场拓展。',
content: '<p>开元云科技宣布完成B轮融资融资金额将用于加速AI智能体工厂产品研发、行业解决方案深化及海外市场拓展。</p>'
}
]
}
},
computed: {
featuredNews() {
return this.newsList.find(item => item.featured)
},
filteredNewsList() {
return this.newsList.filter(item => !item.featured && (this.activeCategory === 'all' || item.category === this.activeCategory))
}
},
methods: {
goAbout() {
this.$router.push('/homePage/about')
}
}
}
</script>
<style scoped lang="less">
@import url('../../../assets/less/news/news.less');
</style>

View File

@ -1,5 +1,5 @@
<template>
<div>
<div class="hospital-page">
<div class="banner">
<img class="bg" src="./img/hospitalBanner.png" alt="">
<div class="textBox">

View File

@ -158,5 +158,9 @@ export default {
</script>
<style scoped>
.train-page {
padding-top: 0;
}
@import './train.css';
</style>

View File

@ -36,7 +36,7 @@
.hero-section {
position: relative;
padding: 80px 24px;
padding: 162px 24px 80px;
overflow: hidden;
}
@ -584,7 +584,7 @@
@media (max-width: 760px) {
.hero-section {
padding: 48px 18px;
padding: 120px 18px 48px;
}
.hero-title {

View File

@ -1,26 +1,19 @@
<template>
<div class="model-page">
<!-- 筛选区 -->
<model-filter
<!-- 统计区 -->
<model-stats :stats="modelStats" />
<!-- 筛选区 -->
<model-filter
:search-form="searchForm"
:model-type-options="modelTypeOptions"
:provider-options="providerOptions"
@search="handleSearch"
@reset="resetSearch"
/>
<!-- 统计区 -->
<model-stats :stats="modelStats" />
<!-- 列表区 -->
<el-card class="model-table-card" shadow="never">
<div class="table-header">
<div>
<h3>模型列表</h3>
<p>展示模型基础信息支持上下架排序编辑等操作</p>
</div>
<el-button size="small" icon="el-icon-refresh" @click="fetchModelList">刷新</el-button>
</div>
<el-tabs v-model="activeStatus" class="model-status-tabs" @tab-click="handleTabChange">
<el-tab-pane label="待上架" name="pending" />

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,5 @@
<template>
<div class="product-service-page" :class="{ 'single-product-page': isSinglePageMode }">
<TopBox v-if="isSinglePageMode" class="single-page-topbox" />
<!-- 产品分类导航 -->
<div v-if="!isSinglePageMode" class="category-nav">
@ -228,7 +227,6 @@
<script>
import { reqNavList, reqNewHomeSync, reqNewHomeFestival } from "@/api/newHome";
import { gotoYuanJingAPI } from '@/api/gotoYuanJing'
import TopBox from '@/views/homePage/components/topBox/index.vue'
const getImageUrlPrefix = () => {
const origin = window.location.origin
@ -246,9 +244,6 @@ const getImageUrlPrefix = () => {
export default {
name: "ProductServicePage",
components: {
TopBox
},
data() {
return {
panelData: [],
@ -270,7 +265,10 @@ export default {
return this.isTokenMarketCategory(this.activeCategory);
},
isSinglePageMode() {
return this.$route.path === '/tokenMarket' || this.$route.query.single === '1' || this.$route.query.single === 'true';
return this.$route.path === '/tokenMarket' ||
this.$route.path === '/homePage/tokenMarket' ||
this.$route.query.single === '1' ||
this.$route.query.single === 'true';
},
currentSubcategories() {
if (!this.activeCategory || !this.panelData.length) return [];
@ -531,7 +529,7 @@ export default {
//
async loadNavData() {
try {
const response = await reqNavList({ url_link: window.location.href });
const response = await reqNavList({ url_link: this.getNavRequestUrl() });
if (response.status && response.data.product_service) {
this.panelData = this.processNavData(response.data.product_service);
}
@ -541,6 +539,15 @@ export default {
}
},
getNavRequestUrl() {
if (!this.isSinglePageMode) {
return window.location.href;
}
const baseUrl = window.location.href.split('#')[0];
const homePath = window.location.hostname.includes('ncmatch.cn') ? '/ncmatchHome/index' : '/homePage/index';
return `${baseUrl}#${homePath}`;
},
// -
processNavData(data) {
return data.map((category, categoryIndex) => {
@ -897,31 +904,24 @@ export default {
<style lang="less" scoped>
.product-service-page {
margin: 0 auto;
padding: 24px;
padding: 82px 24px 24px;
background: #fff;
min-height: calc(100vh - 100px);
&.single-product-page {
height: 100vh;
min-height: 100vh;
padding: 28px;
padding: 82px 0 0;
background: linear-gradient(180deg, #f3f7ff 0%, #ffffff 100%);
overflow-y: auto;
overflow-x: hidden;
.single-page-topbox {
width: 100vw;
margin: -28px calc(50% - 50vw) 24px;
}
.product-content {
max-width: 1180px;
margin-right: auto;
margin-left: auto;
}
.product-content {
margin: 24px auto 0;
padding-right: 28px;
padding-bottom: 40px;
padding-left: 28px;
}
}

View File

@ -0,0 +1,480 @@
# 财务结算接口文档
本文档汇总财务结算相关接口,覆盖供应商/分销商日结、月结费用查询,平台收入查询,结算单创建、审批和记账闭环。
## 通用说明
接口域名: https://dev.opencomputing.cn
金额口径:
- `sales_amount`:销售金额,来源于 `bill.amount`
- `settlement_amount`:应结算金额。
- 供应商:当前账本 `bill_detail.subjectname LIKE '待结转%'``accounting_dir='贷'`
- 分销商:当前账本 `bill_detail.subjectname='分销商存放资金'``accounting_dir='借'``participantid=分销商orgid`
- `platform_income_amount`:平台收入,当前账本 `bill_detail.subjectname IN ('折扣收入', '底价收入')``accounting_dir='贷'`
- 所有正式结算金额只统计已记账账单:`bill.bill_state = '1'`
状态说明:
| 状态 | 含义 |
| --- | --- |
| `draft` | 草稿,已创建结算单但未提交审批 |
| `approving` | 审批中 |
| `approved` | 审批通过,等待或正在记账 |
| `rejected` | 审批拒绝 |
| `settled` | 已完成结算记账 |
| `failed` | 结算记账失败 |
| `cancelled` | 审批撤销 |
推荐调用流程:
```text
summary -> preview -> create -> submit -> apv_callback
```
## 1. 汇总查询
接口:
```text
/bill/finance_settlement_summary.dspy
```
功能:
查询供应商或分销商在指定日结/月结账期内的销售金额、结算金额、平台收入和账单数量。支持按对手方聚合,也支持指定某个供应商或分销商查询。
入参:
| 字段 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `accounting_orgid` | 是 | string | 当前账本机构 ID |
| `counterparty_type` | 是 | string | `supplier` 供应商,`reseller` 分销商 |
| `period_type` | 否 | string | `day``month`,默认 `day` |
| `start_date` | 是 | string | 查询开始日期,格式 `YYYY-MM-DD` |
| `end_date` | 是 | string | 查询结束日期,格式 `YYYY-MM-DD` |
| `counterparty_orgid` | 否 | string | 指定供应商或分销商机构 ID |
| `current_page` | 否 | number | 页码,默认 `1` |
| `page_size` | 否 | number | 每页数量,默认 `20` |
请求示例:
```json
{
"accounting_orgid": "org001",
"counterparty_type": "supplier",
"period_type": "month",
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"current_page": 1,
"page_size": 20
}
```
出参:
| 字段 | 说明 |
| --- | --- |
| `data.summary.sales_amount` | 销售金额合计 |
| `data.summary.settlement_amount` | 结算金额合计 |
| `data.summary.platform_income_amount` | 平台收入合计 |
| `data.summary.bill_count` | 账单数量 |
| `data.items[].period` | 账期,日结为 `YYYY-MM-DD`,月结为 `YYYY-MM` |
| `data.items[].counterparty_orgid` | 对手方机构 ID |
| `data.items[].counterparty_name` | 对手方名称 |
| `data.items[].sales_amount` | 当前行销售金额 |
| `data.items[].settlement_amount` | 当前行结算金额 |
| `data.items[].platform_income_amount` | 当前行平台收入 |
| `data.items[].bill_count` | 当前行账单数量 |
返回示例:
```json
{
"status": true,
"msg": "ok",
"data": {
"accounting_orgid": "org001",
"counterparty_type": "supplier",
"period_type": "month",
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"summary": {
"sales_amount": 1000.0,
"settlement_amount": 700.0,
"platform_income_amount": 300.0,
"bill_count": 10
},
"total_count": 1,
"current_page": 1,
"page_size": 20,
"items": []
}
}
```
## 2. 结算单预览
接口:
```text
/bill/finance_settlement_preview.dspy
```
功能:
创建结算单前预览明细,检查指定账期是否已有结算单,并返回可结算账单明细。
入参:
| 字段 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `accounting_orgid` | 是 | string | 当前账本机构 ID |
| `counterparty_type` | 是 | string | `supplier``reseller` |
| `counterparty_orgid` | 是 | string | 供应商或分销商机构 ID |
| `period_type` | 否 | string | `day``month`,默认 `day` |
| `period_start` | 是 | string | 账期开始日期 |
| `period_end` | 是 | string | 账期结束日期 |
| `current_page` | 否 | number | 页码,默认 `1` |
| `page_size` | 否 | number | 每页数量,默认 `50` |
请求示例:
```json
{
"accounting_orgid": "org001",
"counterparty_type": "reseller",
"counterparty_orgid": "reseller001",
"period_type": "month",
"period_start": "2026-06-01",
"period_end": "2026-06-30"
}
```
出参:
| 字段 | 说明 |
| --- | --- |
| `data.can_create` | 是否可以创建结算单 |
| `data.existing_settlement` | 已存在结算单信息,没有则为 `null` |
| `data.summary` | 汇总金额 |
| `data.items[]` | 账单明细 |
| `data.items[].bill_id` | 账单 ID |
| `data.items[].order_id` | 订单 ID |
| `data.items[].bill_date` | 账单日期 |
| `data.items[].sale_mode` | 销售模式,`0` 折扣,`1` 代付费,`2` 底价 |
| `data.items[].sales_amount` | 销售金额 |
| `data.items[].settlement_amount` | 结算金额 |
| `data.items[].platform_income_amount` | 平台收入 |
## 3. 创建结算单
接口:
```text
/bill/finance_settlement_create.dspy
```
功能:
创建结算单主表和明细快照。创建后状态为 `draft`。同一账本机构、对手方、账期不能重复创建。
入参:
| 字段 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `accounting_orgid` | 是 | string | 当前账本机构 ID |
| `counterparty_type` | 是 | string | `supplier``reseller` |
| `counterparty_orgid` | 是 | string | 供应商或分销商机构 ID |
| `period_type` | 否 | string | `day``month`,默认 `day` |
| `period_start` | 是 | string | 账期开始日期 |
| `period_end` | 是 | string | 账期结束日期 |
| `userid` | 否 | string | 当前操作用户 ID |
请求示例:
```json
{
"accounting_orgid": "org001",
"counterparty_type": "supplier",
"counterparty_orgid": "supplier001",
"period_type": "day",
"period_start": "2026-06-01",
"period_end": "2026-06-01",
"userid": "user001"
}
```
出参:
| 字段 | 说明 |
| --- | --- |
| `data.settlement_id` | 结算单 ID |
| `data.settlement_no` | 结算单号 |
| `data.status` | 初始状态,固定为 `draft` |
| `data.summary` | 创建时锁定的汇总金额 |
## 4. 结算单列表
接口:
```text
/bill/finance_settlement_list.dspy
```
功能:
分页查询结算单主表数据。
入参:
| 字段 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `accounting_orgid` | 是 | string | 当前账本机构 ID |
| `counterparty_type` | 否 | string | `supplier``reseller` |
| `counterparty_orgid` | 否 | string | 对手方机构 ID |
| `status` | 否 | string | 结算单状态 |
| `period_type` | 否 | string | `day``month` |
| `start_date` | 否 | string | 账期范围开始 |
| `end_date` | 否 | string | 账期范围结束 |
| `current_page` | 否 | number | 页码,默认 `1` |
| `page_size` | 否 | number | 每页数量,默认 `20` |
出参:
| 字段 | 说明 |
| --- | --- |
| `data.total_count` | 总数 |
| `data.current_page` | 当前页 |
| `data.page_size` | 每页数量 |
| `data.items[]` | 结算单列表 |
`items[]` 中主要字段:
| 字段 | 说明 |
| --- | --- |
| `id` | 结算单 ID |
| `settlement_no` | 结算单号 |
| `counterparty_type` | 对手方类型 |
| `counterparty_orgid` | 对手方机构 ID |
| `counterparty_name` | 对手方名称 |
| `period_start` | 账期开始 |
| `period_end` | 账期结束 |
| `sales_amount` | 销售金额 |
| `settlement_amount` | 结算金额 |
| `platform_income_amount` | 平台收入 |
| `status` | 结算单状态 |
| `approval_id` | 审批 ID |
## 5. 结算单详情
接口:
```text
/bill/finance_settlement_detail.dspy
```
功能:
查询结算单主表和明细快照。
入参:
| 字段 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `settlement_id` | 是 | string | 结算单 ID |
| `current_page` | 否 | number | 明细页码,默认 `1` |
| `page_size` | 否 | number | 明细每页数量,默认 `100` |
出参:
| 字段 | 说明 |
| --- | --- |
| `data.settlement` | 结算单主表 |
| `data.detail_total_count` | 明细总数 |
| `data.items[]` | 结算明细快照 |
## 6. 提交审批
接口:
```text
/bill/finance_settlement_submit.dspy
```
功能:
`draft``rejected``failed` 状态的结算单提交审批。提交成功后状态更新为 `approving`,并写入 `approval_id`
入参:
| 字段 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `settlement_id` | 是 | string | 结算单 ID |
| `userid` | 是 | string | 当前操作用户 ID |
| `business_name` | 否 | string | 审批业务名,默认 `财务结算` |
请求示例:
```json
{
"settlement_id": "settlement001",
"userid": "user001",
"business_name": "财务结算"
}
```
出参:
| 字段 | 说明 |
| --- | --- |
| `data.settlement_id` | 结算单 ID |
| `data.approval_id` | 审批实例 ID |
| `data.status` | `approving` |
注意:
- `apv_business` 表中需要存在 `business_name='财务结算'` 的审批业务配置。
- 当前账本机构下需要存在角色为 `财务` 的审批用户。
## 7. 审批回调
接口:
```text
/bill/finance_settlement_apv_callback.dspy
```
功能:
处理审批回调。审批通过后自动结算记账:
- 供应商结算:调用现有 `SettleAccounting`
- 分销商结算:写入 `bill``bill_detail``accounting_log``acc_detail``acc_balance`
入参:
| 字段 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `apv_id` | 是 | string | 审批实例 ID也可传 `approval_id` |
| `status` | 是 | string | 审批状态 |
`status` 支持:
| 值 | 说明 |
| --- | --- |
| `start` | 审批中 |
| `agree` | 审批通过,执行结算记账 |
| `refuse` | 审批拒绝 |
| `terminate` | 审批撤销 |
请求示例:
```json
{
"apv_id": "approval001",
"status": "agree"
}
```
出参:
| 字段 | 说明 |
| --- | --- |
| `data[].settlement_id` | 结算单 ID |
| `data[].status` | 处理后的状态 |
| `data[].failure_reason` | 失败原因,仅失败时返回 |
返回示例:
```json
{
"status": true,
"msg": "ok",
"data": [
{
"settlement_id": "settlement001",
"status": "settled"
}
]
}
```
## 8. 数据库迁移 SQL
文件:
```text
b/bill/finance_settlement_migration.sql
```
用途:
- 创建 `finance_settlement`
- 创建 `finance_settlement_detail`
- 已建表场景下补齐 `sale_mode` 字段。
- 提供分销商结算前账户检查 SQL 模板。
## 9. 页面
文件:
```text
finaace_settlement.html
```
用途:
浅色科技风财务结算页面,包含:
- 汇总查询
- 平台收入展示
- 结算单预览
- 创建结算单
- 结算单列表
- 结算单详情
- 提交审批
- 审批回调
## 10. 常见错误
### 查询失败:`unsupported format character`
原因:
SQL 中包含 `%` 通配符时,运行环境可能再次进行 Python 字符串格式化。
处理:
`.dspy` SQL 字符串中使用:
```sql
LIKE '待结转%%'
```
不要写成:
```sql
LIKE '待结转%'
```
### 分销商结算失败:找不到分销商存放资金账户
原因:
分销商结算需要以下账户存在:
- `accounting_orgid = 上级机构`
- `orgid = 分销商机构`
- `subjectname = 分销商存放资金`
以及:
- `accounting_orgid = 上级机构`
- `orgid = 上级机构`
- `subjectname = 资金账号`
处理:
执行 `b/bill/finance_settlement_migration.sql` 中附带的检查 SQL确认账户已开通。

415
finance_settlement.md Normal file
View File

@ -0,0 +1,415 @@
# 财务结算接口文档
本文档汇总财务结算相关接口,覆盖供应商/分销商日结、月结费用查询,平台收入查询,结算单创建、审批和记账闭环。
## 通用说明
接口域名: https://dev.opencomputing.cn
金额口径:
- `sales_amount`:销售金额,来源于 `bill.amount`
- `settlement_amount`:应结算金额。
- 供应商:当前账本 `bill_detail.subjectname LIKE '待结转%'``accounting_dir='贷'`
- 分销商:当前账本 `bill_detail.subjectname='分销商存放资金'``accounting_dir='借'``participantid=分销商orgid`
- `platform_income_amount`:平台收入,当前账本 `bill_detail.subjectname IN ('折扣收入', '底价收入')``accounting_dir='贷'`
- 所有正式结算金额只统计已记账账单:`bill.bill_state = '1'`
状态说明:
| 状态 | 含义 |
| --- | --- |
| `draft` | 草稿,已创建结算单但未提交审批 |
| `approving` | 审批中 |
| `approved` | 审批通过,等待或正在记账 |
| `rejected` | 审批拒绝 |
| `settled` | 已完成结算记账 |
| `failed` | 结算记账失败 |
| `cancelled` | 审批撤销 |
推荐调用流程:
```text
summary -> preview -> create -> submit -> apv_callback
```
## 1. 汇总查询
接口:
```text
/bill/finance_settlement_summary.dspy
```
功能:
查询供应商或分销商在指定日结/月结账期内的销售金额、结算金额、平台收入和账单数量。支持按对手方聚合,也支持指定某个供应商或分销商查询。
入参:
| 字段 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `accounting_orgid` | 是 | string | 当前账本机构 ID |
| `counterparty_type` | 是 | string | `supplier` 供应商,`reseller` 分销商 |
| `period_type` | 否 | string | `day``month`,默认 `day` |
| `start_date` | 是 | string | 查询开始日期,格式 `YYYY-MM-DD` |
| `end_date` | 是 | string | 查询结束日期,格式 `YYYY-MM-DD` |
| `counterparty_orgid` | 否 | string | 指定供应商或分销商机构 ID |
| `current_page` | 否 | number | 页码,默认 `1` |
| `page_size` | 否 | number | 每页数量,默认 `20` |
请求示例:
```json
{
"accounting_orgid": "org001",
"counterparty_type": "supplier",
"period_type": "month",
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"current_page": 1,
"page_size": 20
}
```
出参:
| 字段 | 说明 |
| --- | --- |
| `data.summary.sales_amount` | 销售金额合计 |
| `data.summary.settlement_amount` | 结算金额合计 |
| `data.summary.platform_income_amount` | 平台收入合计 |
| `data.summary.bill_count` | 账单数量 |
| `data.items[].period` | 账期,日结为 `YYYY-MM-DD`,月结为 `YYYY-MM` |
| `data.items[].counterparty_orgid` | 对手方机构 ID |
| `data.items[].counterparty_name` | 对手方名称 |
| `data.items[].sales_amount` | 当前行销售金额 |
| `data.items[].settlement_amount` | 当前行结算金额 |
| `data.items[].platform_income_amount` | 当前行平台收入 |
| `data.items[].bill_count` | 当前行账单数量 |
返回示例:
```json
{
"status": true,
"msg": "ok",
"data": {
"accounting_orgid": "org001",
"counterparty_type": "supplier",
"period_type": "month",
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"summary": {
"sales_amount": 1000.0,
"settlement_amount": 700.0,
"platform_income_amount": 300.0,
"bill_count": 10
},
"total_count": 1,
"current_page": 1,
"page_size": 20,
"items": []
}
}
```
## 2. 结算单预览
接口:
```text
/bill/finance_settlement_preview.dspy
```
功能:
创建结算单前预览明细,检查指定账期是否已有结算单,并返回可结算账单明细。
入参:
| 字段 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `accounting_orgid` | 是 | string | 当前账本机构 ID |
| `counterparty_type` | 是 | string | `supplier``reseller` |
| `counterparty_orgid` | 是 | string | 供应商或分销商机构 ID |
| `period_type` | 否 | string | `day``month`,默认 `day` |
| `period_start` | 是 | string | 账期开始日期 |
| `period_end` | 是 | string | 账期结束日期 |
| `current_page` | 否 | number | 页码,默认 `1` |
| `page_size` | 否 | number | 每页数量,默认 `50` |
请求示例:
```json
{
"accounting_orgid": "org001",
"counterparty_type": "reseller",
"counterparty_orgid": "reseller001",
"period_type": "month",
"period_start": "2026-06-01",
"period_end": "2026-06-30"
}
```
出参:
| 字段 | 说明 |
| --- | --- |
| `data.can_create` | 是否可以创建结算单 |
| `data.existing_settlement` | 已存在结算单信息,没有则为 `null` |
| `data.summary` | 汇总金额 |
| `data.items[]` | 账单明细 |
| `data.items[].bill_id` | 账单 ID |
| `data.items[].order_id` | 订单 ID |
| `data.items[].bill_date` | 账单日期 |
| `data.items[].sale_mode` | 销售模式,`0` 折扣,`1` 代付费,`2` 底价 |
| `data.items[].sales_amount` | 销售金额 |
| `data.items[].settlement_amount` | 结算金额 |
| `data.items[].platform_income_amount` | 平台收入 |
## 3. 创建结算单
接口:
```text
/bill/finance_settlement_create.dspy
```
功能:
创建结算单主表和明细快照。创建后状态为 `draft`。同一账本机构、对手方、账期不能重复创建。
入参:
| 字段 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `accounting_orgid` | 是 | string | 当前账本机构 ID |
| `counterparty_type` | 是 | string | `supplier``reseller` |
| `counterparty_orgid` | 是 | string | 供应商或分销商机构 ID |
| `period_type` | 否 | string | `day``month`,默认 `day` |
| `period_start` | 是 | string | 账期开始日期 |
| `period_end` | 是 | string | 账期结束日期 |
| `userid` | 否 | string | 当前操作用户 ID |
请求示例:
```json
{
"accounting_orgid": "org001",
"counterparty_type": "supplier",
"counterparty_orgid": "supplier001",
"period_type": "day",
"period_start": "2026-06-01",
"period_end": "2026-06-01",
"userid": "user001"
}
```
出参:
| 字段 | 说明 |
| --- | --- |
| `data.settlement_id` | 结算单 ID |
| `data.settlement_no` | 结算单号 |
| `data.status` | 初始状态,固定为 `draft` |
| `data.summary` | 创建时锁定的汇总金额 |
## 4. 结算单列表
接口:
```text
/bill/finance_settlement_list.dspy
```
功能:
分页查询结算单主表数据。
入参:
| 字段 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `accounting_orgid` | 是 | string | 当前账本机构 ID |
| `counterparty_type` | 否 | string | `supplier``reseller` |
| `counterparty_orgid` | 否 | string | 对手方机构 ID |
| `status` | 否 | string | 结算单状态 |
| `period_type` | 否 | string | `day``month` |
| `start_date` | 否 | string | 账期范围开始 |
| `end_date` | 否 | string | 账期范围结束 |
| `current_page` | 否 | number | 页码,默认 `1` |
| `page_size` | 否 | number | 每页数量,默认 `20` |
出参:
| 字段 | 说明 |
| --- | --- |
| `data.total_count` | 总数 |
| `data.current_page` | 当前页 |
| `data.page_size` | 每页数量 |
| `data.items[]` | 结算单列表 |
`items[]` 中主要字段:
| 字段 | 说明 |
| --- | --- |
| `id` | 结算单 ID |
| `settlement_no` | 结算单号 |
| `counterparty_type` | 对手方类型 |
| `counterparty_orgid` | 对手方机构 ID |
| `counterparty_name` | 对手方名称 |
| `period_start` | 账期开始 |
| `period_end` | 账期结束 |
| `sales_amount` | 销售金额 |
| `settlement_amount` | 结算金额 |
| `platform_income_amount` | 平台收入 |
| `status` | 结算单状态 |
| `approval_id` | 审批 ID |
## 5. 结算单详情
接口:
```text
/bill/finance_settlement_detail.dspy
```
功能:
查询结算单主表和明细快照。
入参:
| 字段 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `settlement_id` | 是 | string | 结算单 ID |
| `current_page` | 否 | number | 明细页码,默认 `1` |
| `page_size` | 否 | number | 明细每页数量,默认 `100` |
出参:
| 字段 | 说明 |
| --- | --- |
| `data.settlement` | 结算单主表 |
| `data.detail_total_count` | 明细总数 |
| `data.items[]` | 结算明细快照 |
## 6. 提交审批
接口:
```text
/bill/finance_settlement_submit.dspy
```
功能:
`draft``rejected``failed` 状态的结算单提交审批。提交成功后状态更新为 `approving`,并写入 `approval_id`
入参:
| 字段 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `settlement_id` | 是 | string | 结算单 ID |
| `userid` | 是 | string | 当前操作用户 ID |
| `business_name` | 否 | string | 审批业务名,默认 `财务结算` |
请求示例:
```json
{
"settlement_id": "settlement001",
"userid": "user001",
"business_name": "财务结算"
}
```
出参:
| 字段 | 说明 |
| --- | --- |
| `data.settlement_id` | 结算单 ID |
| `data.approval_id` | 审批实例 ID |
| `data.status` | `approving` |
注意:
- `apv_business` 表中需要存在 `business_name='财务结算'` 的审批业务配置。
- 当前账本机构下需要存在角色为 `财务` 的审批用户。
## 7. 审批回调
接口:
```text
/bill/finance_settlement_apv_callback.dspy
```
功能:
处理审批回调。审批通过后自动结算记账:
- 供应商结算:调用现有 `SettleAccounting`
- 分销商结算:写入 `bill``bill_detail``accounting_log``acc_detail``acc_balance`
入参:
| 字段 | 必填 | 类型 | 说明 |
| --- | --- | --- | --- |
| `apv_id` | 是 | string | 审批实例 ID也可传 `approval_id` |
| `status` | 是 | string | 审批状态 |
`status` 支持:
| 值 | 说明 |
| --- | --- |
| `start` | 审批中 |
| `agree` | 审批通过,执行结算记账 |
| `refuse` | 审批拒绝 |
| `terminate` | 审批撤销 |
请求示例:
```json
{
"apv_id": "approval001",
"status": "agree"
}
```
出参:
| 字段 | 说明 |
| --- | --- |
| `data[].settlement_id` | 结算单 ID |
| `data[].status` | 处理后的状态 |
| `data[].failure_reason` | 失败原因,仅失败时返回 |
返回示例:
```json
{
"status": true,
"msg": "ok",
"data": [
{
"settlement_id": "settlement001",
"status": "settled"
}
]
}
```
## 8. 页面
浅色科技风财务结算页面,包含:
- 汇总查询
- 平台收入展示
- 结算单预览
- 创建结算单
- 结算单列表
- 结算单详情
- 提交审批
- 审批回调

View File

@ -1 +1 @@
pyinstaller -y --clean kgadget.spec
pyinstaller -y --clean kgadget.spec

View File

@ -0,0 +1,60 @@
# -*- mode: python ; coding: utf-8 -*-
import os
import dataui
from PyInstaller.utils.hooks import collect_dynamic_libs # 新增导入
# 收集所有科学计算库的动态库
numpy_binaries = collect_dynamic_libs('numpy')
# scipy_binaries = collect_dynamic_libs('scipy') # 如果使用了 scipy
pandas_binaries = collect_dynamic_libs('pandas') # 如果使用了 pandas
kafka_binaries = collect_dynamic_libs('confluent_kafka')
# 合并所有动态库列表
all_binaries = kafka_binaries
duipath = os.path.dirname(dataui.__file__)
block_cipher = None
a = Analysis(['../src/kgadget.py'],
pathex=['../src'],
binaries=all_binaries,
datas=[
(f'{duipath}/tmpl/bricks/*.*', 'dataui/tmpl/bricks')
],
hiddenimports=[
'sqlite3',
'aiopg',
'aiomysql'
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='kgadget',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None )

View File

@ -0,0 +1,81 @@
# -*- mode: python ; coding: utf-8 -*-
import os
import dataui
import confluent_kafka
from PyInstaller.utils.hooks import collect_dynamic_libs, collect_submodules
# ---- 定位 confluent_kafka.libs ----
kafka_libs_dir = os.path.join(
os.path.dirname(confluent_kafka.__file__),
'..',
'confluent_kafka.libs'
)
kafka_libs_dir = os.path.normpath(kafka_libs_dir)
if not os.path.exists(kafka_libs_dir):
alt_dir = os.path.join(
os.path.dirname(os.path.dirname(confluent_kafka.__file__)),
'confluent_kafka.libs'
)
if os.path.exists(alt_dir):
kafka_libs_dir = alt_dir
print(f"[SPEC] Kafka libs dir: {kafka_libs_dir}, exists: {os.path.exists(kafka_libs_dir)}")
# ---- 收集 numpy/pandas 动态库(若使用) ----
numpy_binaries = collect_dynamic_libs('numpy') if False else [] # 如果使用,改为 True
pandas_binaries = collect_dynamic_libs('pandas') if False else []
# 我们也可以直接通过 datas 包含它们的 .libs 目录(但更推荐用 collect_dynamic_libs
# 这里我们先用 collect_dynamic_libs 并合并到 binaries
all_binaries = numpy_binaries + pandas_binaries # 加入 kafka 吗?不,我们用 datas
duipath = os.path.dirname(dataui.__file__)
block_cipher = None
a = Analysis(
['../src/kgadget.py'],
pathex=['../src'],
binaries=all_binaries, # 包含 numpy/pandas 的 .so
datas=[
(f'{duipath}/tmpl/bricks/*.*', 'dataui/tmpl/bricks'),
(kafka_libs_dir, 'confluent_kafka.libs'), # 复制整个 kafka 目录
],
hiddenimports=[
'sqlite3',
'aiopg',
'aiomysql',
'confluent_kafka.admin',
],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher,
noarchive=False
)
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
[],
name='kgadget',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=False, # 务必关闭 UPX
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
onefile=False # 显式指定 onefile=False
)