1012 lines
58 KiB
JavaScript
1012 lines
58 KiB
JavaScript
/**
|
||
* company.js - 企业数据管理逻辑(列表+筛选+分页 / 新增编辑弹窗 / 产品 / 官媒 / 导入导出 / 详情)
|
||
* v1.0.18:
|
||
* - 检索区:筛选字段下拉(全部字段/指定字段,与检索词联动)+ 行业下拉 + 企业类型下拉(去掉国家/地区框)
|
||
* - 新增/编辑:Tab 卡改为 基本信息|财务信息|资质认证;基本信息内左侧文字锚导航(工商信息/联系方式/行业归属/业务类型/来源)
|
||
* - 表单字段:公司名称→企业名称、法律形式→企业类型(字典下拉)、删除英文名称;资质认证增加 级别/颁证机构
|
||
* - 产品弹窗:展示 产品品类/基本定位/包含系列/状态/更新日期 + 新增产品按钮(EAV 参数)
|
||
* - 新增「官媒」入口:公司媒体清单 + 新增官媒按钮
|
||
*/
|
||
$(function () {
|
||
renderShell('企业数据', '数据管理 / 企业数据');
|
||
renderPage();
|
||
initPage('company', function (user) {
|
||
if (!checkPagePermission('company')) return;
|
||
loadDicts().then(function (dicts) {
|
||
window._companyDicts = dicts;
|
||
fillSearchDicts(dicts);
|
||
loadList(1);
|
||
}).catch(function () {
|
||
loadList(1);
|
||
});
|
||
});
|
||
|
||
var currentPage = 1;
|
||
|
||
/** 渲染页面内容(工具栏+表格+分页) */
|
||
function renderPage() {
|
||
$('#page-content').html(
|
||
'<div class="card">' +
|
||
' <div class="toolbar">' +
|
||
' <button class="btn" id="btn-filter" title="按字段设置多个筛选条件(支持 且/或 逻辑)">筛选</button>' +
|
||
' <div class="search-wrap">' +
|
||
' <select id="search-field"><option value="">全字段</option>' +
|
||
' <option value="name_zh">企业名称</option><option value="name_en">英文名称</option>' +
|
||
' <option value="registration_number">注册号</option><option value="legal_representative">法定代表人</option>' +
|
||
' <option value="address">注册地址</option><option value="industry">行业</option>' +
|
||
' <option value="industry_subdivision">行业细分</option><option value="website">官网</option>' +
|
||
' <option value="source_channel">来源渠道</option><option value="source_detail">来源详情</option>' +
|
||
' <option value="business_scope">经营范围</option><option value="stock_code">股票代码</option></select>' +
|
||
' <input type="text" id="search-keyword" placeholder="输入关键词,回车搜索">' +
|
||
' <span class="search-icon" id="btn-search" title="搜索"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg></span>' +
|
||
' </div>' +
|
||
' <select id="search-industry" data-filter="industry"><option value="">全部行业</option></select>' +
|
||
' <select id="search-company-type" data-filter="company_type"><option value="">全部业务类型</option></select>' +
|
||
' <button class="btn" id="btn-reset">重置</button>' +
|
||
' <span class="spacer"></span>' +
|
||
' <button class="btn btn-success" id="btn-add">+ 新增</button>' +
|
||
' <button class="btn btn-warning" id="btn-import">导入CSV</button>' +
|
||
' <button class="btn" id="btn-export">导出</button>' +
|
||
' </div>' +
|
||
' <div class="table-wrap"><table class="grid">' +
|
||
' <thead><tr><th><input type="checkbox" id="check-all"></th><th>ID</th><th>企业名称</th><th>行业</th><th>行业细分</th><th>国家</th><th>业务角色</th><th>注册号</th><th>法人</th><th>上市</th><th>创建时间</th><th>操作</th></tr></thead>' +
|
||
' <tbody id="company-tbody"></tbody>' +
|
||
' </table></div>' +
|
||
' <div class="pagination" id="pagination"></div>' +
|
||
'</div>'
|
||
);
|
||
$('#check-all').on('change', function () { $('.row-check').prop('checked', this.checked); });
|
||
}
|
||
|
||
/** 填充检索区字典下拉(行业/企业类型) */
|
||
function fillSearchDicts(dicts) {
|
||
var indHtml = '<option value="">全部行业</option>';
|
||
(dicts.industries || []).forEach(function (i) {
|
||
indHtml += '<option value="' + escHtml(i.name) + '">' + escHtml(i.name) + '</option>';
|
||
});
|
||
$('#search-industry').html(indHtml);
|
||
|
||
var ctHtml = '<option value="">全部企业类型</option>';
|
||
(dicts.company_types || []).forEach(function (t) {
|
||
ctHtml += '<option value="' + escHtml(t.name) + '">' + escHtml(t.name) + '</option>';
|
||
});
|
||
$('#search-company-type').html(ctHtml);
|
||
}
|
||
|
||
/* ---------- 列表 ---------- */
|
||
var companyFilters = { logic: 'and', conditions: [] }; // 筛选弹窗条件(多字段 + 且/或)
|
||
|
||
function loadList(page) {
|
||
currentPage = page;
|
||
var params = {
|
||
field: $('#search-field').val(),
|
||
keyword: $.trim($('#search-keyword').val()),
|
||
industry: $('#search-industry').val(),
|
||
company_type: $('#search-company-type').val(),
|
||
page: page,
|
||
limit: PAGE_SIZE
|
||
};
|
||
// 筛选弹窗条件(多字段 + 逻辑关系)
|
||
if (companyFilters.conditions.length) {
|
||
params.filters = JSON.stringify(companyFilters.conditions);
|
||
params.filter_logic = companyFilters.logic;
|
||
}
|
||
// 空值不传
|
||
Object.keys(params).forEach(function (k) {
|
||
if (params[k] === '') delete params[k];
|
||
});
|
||
|
||
httpGet('company/list.php', params).then(function (data) {
|
||
var rows = data.list || [];
|
||
var html = '';
|
||
rows.forEach(function (r) {
|
||
html += '<tr>' +
|
||
'<td><input type="checkbox" class="row-check" value="' + r.id + '"></td>' +
|
||
'<td>' + r.id + '</td>' +
|
||
'<td title="' + escHtml(r.name_zh || r.name_en || '') + '">' + escHtml(r.name_zh || r.name_en || '-') + '</td>' +
|
||
'<td>' + escHtml(r.industry || '-') + '</td>' +
|
||
'<td>' + escHtml(r.industry_subdivision || '-') + '</td>' +
|
||
'<td>' + escHtml(r.country || '-') + '</td>' +
|
||
'<td>' + escHtml(r.business_role || '-') + '</td>' +
|
||
'<td>' + escHtml(r.registration_number || '-') + '</td>' +
|
||
'<td>' + escHtml(r.legal_representative || '-') + '</td>' +
|
||
'<td>' + (r.is_listed ? '<span class="tag">上市</span>' : '-') + '</td>' +
|
||
'<td>' + fmtDate(r.created_at) + '</td>' +
|
||
'<td class="ops">' +
|
||
' <a onclick="viewCompany(' + r.id + ')">详情</a>' +
|
||
' <a onclick="viewEmployees(' + r.id + ')">员工</a>' +
|
||
' <a onclick="viewProducts(' + r.id + ')">产品</a>' +
|
||
' <a onclick="viewOfficialMedia(' + r.id + ')">官媒</a>' +
|
||
' <a onclick="viewIndustryChain(' + r.id + ')">产业链</a>' +
|
||
' <a onclick="editCompany(' + r.id + ')">编辑</a>' +
|
||
'</td></tr>';
|
||
});
|
||
if (!rows.length) {
|
||
html = '<tr><td colspan="12" class="empty-tip" style="padding:40px 0;">暂无数据</td></tr>';
|
||
}
|
||
$('#company-tbody').html(html);
|
||
renderPagination($('#pagination'), data, loadList);
|
||
});
|
||
}
|
||
|
||
/* ---------- 检索:搜索(字段范围+关键词) / 筛选弹窗 / 行业+业务类型快速筛选 ---------- */
|
||
$('#btn-search').on('click', function () { loadList(1); });
|
||
$('#search-keyword').on('keydown', function (e) { if (e.keyCode === 13) loadList(1); });
|
||
$('#search-industry, #search-company-type').on('change', function () { loadList(1); });
|
||
$('#btn-reset').on('click', function () {
|
||
$('#search-field').val('');
|
||
$('#search-keyword').val('');
|
||
$('#search-industry').val('');
|
||
$('#search-company-type').val('');
|
||
companyFilters = { logic: 'and', conditions: [] };
|
||
loadList(1);
|
||
});
|
||
|
||
/* ---------- 筛选弹窗:多字段条件 + 且/或 逻辑关系 ---------- */
|
||
var FILTER_FIELDS = [
|
||
['name_zh', '企业名称'], ['name_en', '英文名称'], ['registration_number', '注册号'],
|
||
['legal_representative', '法定代表人'], ['address', '注册地址'], ['country', '国家/地区'],
|
||
['industry', '行业'], ['industry_subdivision', '行业细分'], ['legal_form', '企业类型'],
|
||
['business_role', '业务角色'], ['website', '官网'], ['source_channel', '来源渠道'],
|
||
['source_detail', '来源详情'], ['business_scope', '经营范围'], ['stock_code', '股票代码'],
|
||
['established_date', '成立日期'], ['latest_employee_count', '最新员工数'],
|
||
['latest_annual_revenue', '最新年营收']
|
||
];
|
||
var FILTER_OPS = [
|
||
['contains', '包含'], ['eq', '等于'], ['neq', '不等于'],
|
||
['starts_with', '开头是'], ['ends_with', '结尾是'],
|
||
['gt', '大于'], ['lt', '小于'], ['gte', '大于等于'], ['lte', '小于等于'],
|
||
['is_empty', '为空'], ['is_not_empty', '不为空']
|
||
];
|
||
|
||
function filterFieldOptions(cur) {
|
||
var h = '';
|
||
FILTER_FIELDS.forEach(function (f) {
|
||
h += '<option value="' + f[0] + '"' + (f[0] === cur ? ' selected' : '') + '>' + f[1] + '</option>';
|
||
});
|
||
return h;
|
||
}
|
||
function filterOpOptions(cur) {
|
||
var h = '';
|
||
FILTER_OPS.forEach(function (o) {
|
||
h += '<option value="' + o[0] + '"' + (o[0] === cur ? ' selected' : '') + '>' + o[1] + '</option>';
|
||
});
|
||
return h;
|
||
}
|
||
function filterRowHtml(c) {
|
||
c = c || {};
|
||
var valInput = (c.op === 'is_empty' || c.op === 'is_not_empty')
|
||
? '<input type="text" value="" disabled placeholder="(无需填值)" style="background:#f2f4f8;color:#8a94a6;width:180px;">'
|
||
: '<input type="text" value="' + escHtml(c.value || '') + '" placeholder="条件值" style="width:180px;">';
|
||
return '<div class="filter-row">' +
|
||
' <select class="f-field" style="width:150px;">' + filterFieldOptions(c.field) + '</select>' +
|
||
' <select class="f-op" style="width:110px;">' + filterOpOptions(c.op) + '</select>' +
|
||
valInput +
|
||
' <button type="button" class="btn btn-sm btn-danger" onclick="$(this).closest(\'.filter-row\').remove()">删除</button>' +
|
||
'</div>';
|
||
}
|
||
|
||
window.openFilterDialog = function () {
|
||
var logicHtml =
|
||
'<label style="margin-right:14px;font-size:13px;"><input type="radio" name="f-logic" value="and"' +
|
||
(companyFilters.logic !== 'or' ? ' checked' : '') + '> 且(同时满足)</label>' +
|
||
'<label style="font-size:13px;"><input type="radio" name="f-logic" value="or"' +
|
||
(companyFilters.logic === 'or' ? ' checked' : '') + '> 或(任一满足)</label>';
|
||
var rowsHtml = '';
|
||
if (companyFilters.conditions.length) {
|
||
companyFilters.conditions.forEach(function (c) { rowsHtml += filterRowHtml(c); });
|
||
} else {
|
||
rowsHtml = filterRowHtml(null);
|
||
}
|
||
var content =
|
||
'<div style="padding:16px 20px 6px;">' +
|
||
' <div style="margin-bottom:10px;font-size:13px;color:#5a6472;">每个字段是一个筛选条件,不同条件之间可为「且」「或」关系:</div>' +
|
||
' <div style="margin-bottom:10px;">' + logicHtml + '</div>' +
|
||
' <div id="filter-rows">' + rowsHtml + '</div>' +
|
||
' <button type="button" class="btn btn-sm" id="btn-add-filter" style="margin-top:8px;">+ 添加条件</button>' +
|
||
'</div>' +
|
||
'<div class="dialog-footer"><button type="button" class="btn" id="filter-cancel">取消</button>' +
|
||
'<button type="button" class="btn btn-primary" id="filter-apply">应用筛选</button></div>';
|
||
var idx = Dialog.open({
|
||
title: '设置筛选条件',
|
||
area: ['620px', 'auto'],
|
||
content: content,
|
||
btn: false
|
||
});
|
||
$('#btn-add-filter').on('click', function () { $('#filter-rows').append(filterRowHtml(null)); });
|
||
$('#filter-cancel').on('click', function () { Dialog.close(idx); });
|
||
$('#filter-apply').on('click', function () {
|
||
var logic = $('input[name="f-logic"]:checked').val() || 'and';
|
||
var conds = [];
|
||
$('#filter-rows .filter-row').each(function () {
|
||
var field = $(this).find('.f-field').val();
|
||
var op = $(this).find('.f-op').val();
|
||
var value = $.trim($(this).find('input[type="text"]').val());
|
||
if (!field || !op) return;
|
||
if (op !== 'is_empty' && op !== 'is_not_empty' && value === '') return; // 无值且需要值的条件跳过
|
||
conds.push({ field: field, op: op, value: value });
|
||
});
|
||
companyFilters = { logic: logic, conditions: conds };
|
||
Dialog.close(idx);
|
||
loadList(1);
|
||
});
|
||
};
|
||
$('#btn-filter').on('click', function () { openFilterDialog(); });
|
||
|
||
/* ---------- 新增/编辑 ---------- */
|
||
$('#btn-add').on('click', function () {
|
||
httpGet('company/cert_types.php').then(function (d) {
|
||
loadDicts().then(function (dicts) {
|
||
window._companyDicts = dicts;
|
||
openForm(null, [], [], [], d.types || [], dicts);
|
||
});
|
||
});
|
||
});
|
||
window.editCompany = function (id) {
|
||
httpGet('company/detail.php', { id: id }).then(function (d) {
|
||
loadDicts().then(function (dicts) {
|
||
window._companyDicts = dicts;
|
||
openForm(d.company, d.financials, d.certifications, d.accounts || [], d.certification_types, dicts);
|
||
});
|
||
});
|
||
};
|
||
|
||
/** 拉取数据字典(国家/行业/来源渠道/企业类型),供表单与检索使用 */
|
||
function loadDicts() {
|
||
return httpGet('common/dicts.php', { type: 'all' }).catch(function () {
|
||
return { countries: [], industries: [], source_channels: [], company_types: [] };
|
||
});
|
||
}
|
||
|
||
/** 生成下拉选项:value 与当前值匹配则选中;若当前值不在字典中则追加一个选项保留原值 */
|
||
function dictOptions(list, cur, labelKey) {
|
||
var html = '<option value="">-</option>';
|
||
var found = false;
|
||
(list || []).forEach(function (item) {
|
||
var name = item[labelKey || 'name'];
|
||
var sel = (String(name) === String(cur)) ? ' selected' : '';
|
||
if (sel) found = true;
|
||
html += '<option value="' + escHtml(name) + '"' + sel + '>' + escHtml(name) + '</option>';
|
||
});
|
||
if (cur && !found) {
|
||
html += '<option value="' + escHtml(cur) + '" selected>' + escHtml(cur) + '(自定义)</option>';
|
||
}
|
||
return html;
|
||
}
|
||
|
||
/* ============================================================
|
||
* 新增/编辑弹窗:Tab = 基本信息 | 财务信息 | 资质认证
|
||
* 基本信息内左侧文字锚导航:工商信息 / 联系方式 / 行业归属 / 业务类型 / 来源
|
||
* ============================================================ */
|
||
function openForm(company, financials, certifications, accounts, certTypes, dicts) {
|
||
var isEdit = !!company;
|
||
var c = company || {};
|
||
financials = financials || [];
|
||
certifications = certifications || [];
|
||
accounts = accounts || [];
|
||
certTypes = certTypes || [];
|
||
dicts = dicts || {};
|
||
|
||
// ---- 基本信息 Tab(含左侧锚导航 + 5 个分区) ----
|
||
var secBiz =
|
||
'<div class="form-sec" id="sec-biz">' +
|
||
' <div class="form-sec-title">工商信息</div>' +
|
||
' <div class="form-grid">' +
|
||
' <div class="form-item"><label>企业名称<span class="req">*</span></label>' +
|
||
' <div style="display:flex;gap:8px;align-items:center;">' +
|
||
' <input type="text" name="name_zh" value="' + escHtml(c.name_zh) + '" style="width:60%;flex:0 0 auto;">' +
|
||
' <button type="button" class="btn btn-sm" id="btn-gongshang-query" title="预留:后续接入工商查询API,自动填写企业名称/注册号/注册地址等">工商查询</button>' +
|
||
' </div></div>' +
|
||
' <div class="form-item"><label>国家/地区</label><select name="country">' + dictOptions(dicts.countries, c.country) + '</select></div>' +
|
||
' <div class="form-item"><label>注册号</label><input type="text" name="registration_number" value="' + escHtml(c.registration_number) + '"></div>' +
|
||
' <div class="form-item"><label>注册地址</label><input type="text" name="address" value="' + escHtml(c.address) + '"></div>' +
|
||
' <div class="form-item"><label>企业类型</label><select name="legal_form">' + dictOptions(dicts.company_types, c.legal_form) + '</select></div>' +
|
||
' <div class="form-item"><label>法定代表人</label><input type="text" name="legal_representative" value="' + escHtml(c.legal_representative) + '"></div>' +
|
||
' <div class="form-item"><label>成立日期</label><input type="date" name="established_date" value="' + escHtml(c.established_date) + '"></div>' +
|
||
' <div class="form-item"><label>注册资本(万元)</label><input type="text" name="registered_capital" value="' + escHtml(c.registered_capital) + '"></div>' +
|
||
' <div class="form-item full"><label>经营范围</label><textarea name="business_scope">' + escHtml(c.business_scope) + '</textarea></div>' +
|
||
' </div></div>';
|
||
|
||
// 联系方式(social_accounts,整表替换)
|
||
var accountRowsHtml = '';
|
||
if (!accounts.length) {
|
||
accountRowsHtml = accountRowHtml(null);
|
||
} else {
|
||
accounts.forEach(function (a) { accountRowsHtml += accountRowHtml(a); });
|
||
}
|
||
var secContact =
|
||
'<div class="form-sec" id="sec-contact">' +
|
||
' <div class="form-sec-title">联系方式' +
|
||
' <button type="button" class="btn btn-sm" id="add-account-row" style="margin-left:10px;">+ 添加</button></div>' +
|
||
' <div id="account-rows">' + accountRowsHtml + '</div>' +
|
||
' <div style="font-size:12px;color:#8a94a6;margin-top:6px;">如:官网、公众号、微博、抖音、领英等平台账号</div>' +
|
||
'</div>';
|
||
|
||
var secIndustry =
|
||
'<div class="form-sec" id="sec-industry">' +
|
||
' <div class="form-sec-title">行业归属</div>' +
|
||
' <div class="form-grid">' +
|
||
' <div class="form-item"><label>行业</label><select name="industry">' + dictOptions(dicts.industries, c.industry) + '</select></div>' +
|
||
' <div class="form-item"><label>行业细分</label><input type="text" name="industry_subdivision" value="' + escHtml(c.industry_subdivision) + '"></div>' +
|
||
' <div class="form-item"><label>官网</label><input type="text" name="website" value="' + escHtml(c.website) + '"></div>' +
|
||
' </div></div>';
|
||
|
||
var secBizType =
|
||
'<div class="form-sec" id="sec-biztype">' +
|
||
' <div class="form-sec-title">业务类型</div>' +
|
||
' <div class="form-grid">' +
|
||
' <div class="form-item"><label>业务角色</label><select name="business_role">' + roleOptions(c.business_role) + '</select></div>' +
|
||
' </div></div>';
|
||
|
||
var secSource =
|
||
'<div class="form-sec" id="sec-source">' +
|
||
' <div class="form-sec-title">来源</div>' +
|
||
' <div class="form-grid">' +
|
||
' <div class="form-item"><label>来源渠道</label><select name="source_channel">' + dictOptions(dicts.source_channels, c.source_channel) + '</select></div>' +
|
||
' <div class="form-item"><label>来源详情</label><input type="text" name="source_detail" value="' + escHtml(c.source_detail) + '" placeholder="如:华南工博会"></div>' +
|
||
' </div></div>';
|
||
|
||
var bizHtml =
|
||
'<div class="form-anchor-layout">' +
|
||
' <div class="form-anchor-nav">' +
|
||
' <a href="#sec-biz" class="anchor-link active">工商信息</a>' +
|
||
' <a href="#sec-contact" class="anchor-link">联系方式</a>' +
|
||
' <a href="#sec-industry" class="anchor-link">行业归属</a>' +
|
||
' <a href="#sec-biztype" class="anchor-link">业务类型</a>' +
|
||
' <a href="#sec-source" class="anchor-link">来源</a>' +
|
||
' </div>' +
|
||
' <div class="form-anchor-body">' + secBiz + secContact + secIndustry + secBizType + secSource + '</div>' +
|
||
'</div>';
|
||
|
||
// ---- 财务信息 Tab(保持不变) ----
|
||
var finRowsHtml = '';
|
||
if (!financials.length) {
|
||
finRowsHtml = finRowHtml(null);
|
||
} else {
|
||
financials.forEach(function (f) { finRowsHtml += finRowHtml(f); });
|
||
}
|
||
var finHtml =
|
||
'<div class="form-grid">' +
|
||
' <div class="form-item"><label>是否上市</label><select name="is_listed">' +
|
||
' <option value="0"' + (c.is_listed ? '' : ' selected') + '>否</option>' +
|
||
' <option value="1"' + (c.is_listed ? ' selected' : '') + '>是</option></select></div>' +
|
||
' <div class="form-item"><label>股票代码</label><input type="text" name="stock_code" value="' + escHtml(c.stock_code) + '"></div>' +
|
||
' <div class="form-item"><label>最新员工数</label><input type="number" name="latest_employee_count" value="' + escHtml(c.latest_employee_count) + '"></div>' +
|
||
' <div class="form-item"><label>最新年营收</label><input type="text" name="latest_annual_revenue" value="' + escHtml(c.latest_annual_revenue) + '"></div>' +
|
||
'</div>' +
|
||
'<div style="display:flex;justify-content:space-between;align-items:center;margin:16px 0 8px;">' +
|
||
' <b style="font-size:13px;color:#1e2a3a;">年度财务明细(单位:万元)</b>' +
|
||
' <button type="button" class="btn btn-sm" id="add-fin-row">+ 添加年度</button>' +
|
||
'</div>' +
|
||
'<div class="table-wrap"><table class="grid fin-tbl" style="font-size:12px;">' +
|
||
' <thead><tr><th>财年</th><th>员工数</th><th>总营收</th><th>净利润</th><th>总资产</th><th>总负债</th><th>所有者权益</th><th>毛利率(%)</th><th>净利率(%)</th><th>资产负债率(%)</th><th>财务报表链接</th><th>数据来源</th><th>操作</th></tr></thead>' +
|
||
' <tbody id="fin-tbody">' + finRowsHtml + '</tbody>' +
|
||
'</table></div>';
|
||
|
||
// ---- 资质认证 Tab(含级别/颁证机构) ----
|
||
var certRowsHtml = '';
|
||
if (!certifications.length) {
|
||
certRowsHtml = certRowHtml(null, certTypes);
|
||
} else {
|
||
certifications.forEach(function (ct) { certRowsHtml += certRowHtml(ct, certTypes); });
|
||
}
|
||
var certHtml =
|
||
'<div style="display:flex;justify-content:space-between;align-items:center;margin:0 0 8px;">' +
|
||
' <b style="font-size:13px;color:#1e2a3a;">资质认证</b>' +
|
||
' <button type="button" class="btn btn-sm" id="add-cert-row">+ 添加认证</button>' +
|
||
'</div>' +
|
||
'<div id="cert-rows">' + certRowsHtml + '</div>' +
|
||
'<div style="font-size:12px;color:#8a94a6;margin-top:8px;">如:瞪羚企业、国家高新技术企业、专精特新企业、ISO9001认证等</div>';
|
||
|
||
var content =
|
||
'<form id="company-form" style="padding:14px 22px 4px;">' +
|
||
' <div class="edit-tabs">' +
|
||
' <div class="edit-tabs-head">' +
|
||
' <span class="edit-tab active" data-tab="biz" onclick="switchEditTab(this)">基本信息</span>' +
|
||
' <span class="edit-tab" data-tab="fin" onclick="switchEditTab(this)">财务信息</span>' +
|
||
' <span class="edit-tab" data-tab="cert" onclick="switchEditTab(this)">资质认证</span>' +
|
||
' </div>' +
|
||
' <div class="edit-tabs-body">' +
|
||
' <div class="edit-pane" id="edit-pane-biz">' + bizHtml + '</div>' +
|
||
' <div class="edit-pane" id="edit-pane-fin" style="display:none;">' + finHtml + '</div>' +
|
||
' <div class="edit-pane" id="edit-pane-cert" style="display:none;">' + certHtml + '</div>' +
|
||
' </div>' +
|
||
' </div>' +
|
||
'<div class="dialog-footer"><button type="button" class="btn" id="form-cancel">取消</button>' +
|
||
'<button type="submit" class="btn btn-primary">保存</button></div>' +
|
||
'</form>';
|
||
|
||
var idx = Dialog.open({
|
||
title: isEdit ? '编辑企业' : '新增企业',
|
||
area: ['860px', 'auto'],
|
||
content: content,
|
||
btn: false
|
||
});
|
||
|
||
bindAnchorNav();
|
||
|
||
$('#form-cancel').on('click', function () { Dialog.close(idx); });
|
||
$('#add-fin-row').on('click', function () { $('#fin-tbody').append(finRowHtml(null)); });
|
||
$('#add-cert-row').on('click', function () { $('#cert-rows').append(certRowHtml(null, certTypes)); });
|
||
$('#add-account-row').on('click', function () { $('#account-rows').append(accountRowHtml(null)); });
|
||
// 工商查询按钮(预留:后续接入工商查询API自动填写)
|
||
$('#btn-gongshang-query').on('click', function () {
|
||
Dialog.alert('工商查询API预留中,接入后可通过企业名称自动查询并填写企业名称、注册号、注册地址等信息');
|
||
});
|
||
|
||
$('#company-form').on('submit', function (e) {
|
||
e.preventDefault();
|
||
var fd = new FormData(this);
|
||
var nameZh = fd.get('name_zh');
|
||
if (isEdit) fd.delete('display_name'); // 编辑不允许改显示名称
|
||
if (isEdit) fd.append('id', company.id); // 编辑必须带 id,否则 update.php 报参数错误
|
||
if (!nameZh) {
|
||
Dialog.error('企业名称为必填项');
|
||
return;
|
||
}
|
||
|
||
// 年度财务明细(整表替换)
|
||
var financials = [];
|
||
$('#fin-tbody .fin-row').each(function () {
|
||
var $y = $(this);
|
||
var year = $.trim($y.find('[name="fin-fiscal_year"]').val());
|
||
if (!year) return;
|
||
financials.push({
|
||
fiscal_year: year,
|
||
employee_count: $y.find('[name="fin-employee_count"]').val(),
|
||
total_revenue: $y.find('[name="fin-total_revenue"]').val(),
|
||
net_profit: $y.find('[name="fin-net_profit"]').val(),
|
||
total_assets: $y.find('[name="fin-total_assets"]').val(),
|
||
total_liabilities: $y.find('[name="fin-total_liabilities"]').val(),
|
||
owner_equity: $y.find('[name="fin-owner_equity"]').val(),
|
||
gross_margin: $y.find('[name="fin-gross_margin"]').val(),
|
||
net_margin: $y.find('[name="fin-net_margin"]').val(),
|
||
debt_ratio: $y.find('[name="fin-debt_ratio"]').val(),
|
||
financial_report_url: $y.find('[name="fin-financial_report_url"]').val(),
|
||
data_source: $y.find('[name="fin-data_source"]').val()
|
||
});
|
||
});
|
||
fd.append('financials', JSON.stringify(financials));
|
||
|
||
// 资质认证(整表替换,含级别/颁证机构)
|
||
var certs = [];
|
||
$('#cert-rows .cert-row').each(function () {
|
||
var $r = $(this);
|
||
var tid = $r.find('[name="cert-type"]').val();
|
||
if (!tid) return;
|
||
certs.push({
|
||
certification_type_id: tid,
|
||
certificate_number: $r.find('[name="cert-number"]').val(),
|
||
level: $r.find('[name="cert-level"]').val(),
|
||
issuing_authority: $r.find('[name="cert-issuer"]').val(),
|
||
issue_date: $r.find('[name="cert-issue"]').val(),
|
||
expiry_date: $r.find('[name="cert-expiry"]').val()
|
||
});
|
||
});
|
||
fd.append('certifications', JSON.stringify(certs));
|
||
|
||
// 联系方式(整表替换)
|
||
var accounts = [];
|
||
$('#account-rows .account-row').each(function () {
|
||
var $r = $(this);
|
||
var platform = $.trim($r.find('[name="acc-platform"]').val());
|
||
var accountId = $.trim($r.find('[name="acc-account"]').val());
|
||
if (!platform || !accountId) return;
|
||
accounts.push({
|
||
platform: platform,
|
||
account_id: accountId,
|
||
profile_url: $r.find('[name="acc-url"]').val(),
|
||
remark: $r.find('[name="acc-remark"]').val(),
|
||
is_active: $r.find('[name="acc-active"]').val(),
|
||
is_defult: $r.find('[name="acc-defult"]').prop('checked') ? 1 : 0
|
||
});
|
||
});
|
||
fd.append('accounts', JSON.stringify(accounts));
|
||
|
||
httpPost(isEdit ? 'company/update.php' : 'company/add.php', fd, true).then(function () {
|
||
Dialog.success('保存成功', function () {
|
||
Dialog.close(idx);
|
||
loadList(currentPage);
|
||
});
|
||
});
|
||
});
|
||
}
|
||
|
||
/* ---------- 编辑弹窗 Tab 切换 ---------- */
|
||
window.switchEditTab = function (el) {
|
||
var $tabs = $(el).closest('.edit-tabs');
|
||
$tabs.find('.edit-tab').removeClass('active');
|
||
$(el).addClass('active');
|
||
$tabs.find('.edit-pane').hide();
|
||
$('#edit-pane-' + $(el).data('tab')).show();
|
||
};
|
||
|
||
/** 基本信息内左侧锚点导航:点击平滑滚动 + 高亮 */
|
||
function bindAnchorNav() {
|
||
$('.form-anchor-nav .anchor-link').off('click').on('click', function (e) {
|
||
e.preventDefault();
|
||
var $target = $($(this).attr('href'));
|
||
var $body = $target.closest('.edit-pane');
|
||
// 若锚点所在分区不在当前可见 Tab,先切到对应 Tab
|
||
if (!$body.is(':visible')) {
|
||
var tab = $body.attr('id').replace('edit-pane-', '');
|
||
var $tabEl = $('.edit-tabs-head .edit-tab[data-tab="' + tab + '"]');
|
||
if ($tabEl.length) switchEditTab($tabEl[0]);
|
||
}
|
||
var offset = $target.offset();
|
||
if (offset) {
|
||
$('.edit-tabs-body').animate({ scrollTop: $target.offset().top - $('.edit-tabs-body').offset().top + $('.edit-tabs-body').scrollTop() }, 200);
|
||
}
|
||
$('.form-anchor-nav .anchor-link').removeClass('active');
|
||
$(this).addClass('active');
|
||
});
|
||
// 滚动时高亮当前分区
|
||
var $secs = $('.form-anchor-body .form-sec');
|
||
$('.edit-tabs-body').off('scroll.anchor').on('scroll.anchor', function () {
|
||
var top = $(this).scrollTop() + 60;
|
||
var currentId = null;
|
||
$secs.each(function () {
|
||
if ($(this).position().top <= top) currentId = $(this).attr('id');
|
||
});
|
||
if (currentId) {
|
||
$('.form-anchor-nav .anchor-link').removeClass('active');
|
||
$('.form-anchor-nav .anchor-link[href="#' + currentId + '"]').addClass('active');
|
||
}
|
||
});
|
||
}
|
||
|
||
/** 年度财务明细行模板(列表形式,一行一个财年) */
|
||
function finRowHtml(f) {
|
||
f = f || {};
|
||
var empty = function (v) { return (v === null || v === undefined) ? '' : v; };
|
||
return '<tr class="fin-row">' +
|
||
'<td><input type="number" name="fin-fiscal_year" min="1990" max="2100" placeholder="2024" value="' + escHtml(empty(f.fiscal_year)) + '"></td>' +
|
||
'<td><input type="number" name="fin-employee_count" value="' + escHtml(empty(f.employee_count)) + '"></td>' +
|
||
'<td><input type="text" name="fin-total_revenue" value="' + escHtml(empty(f.total_revenue)) + '"></td>' +
|
||
'<td><input type="text" name="fin-net_profit" value="' + escHtml(empty(f.net_profit)) + '"></td>' +
|
||
'<td><input type="text" name="fin-total_assets" value="' + escHtml(empty(f.total_assets)) + '"></td>' +
|
||
'<td><input type="text" name="fin-total_liabilities" value="' + escHtml(empty(f.total_liabilities)) + '"></td>' +
|
||
'<td><input type="text" name="fin-owner_equity" value="' + escHtml(empty(f.owner_equity)) + '"></td>' +
|
||
'<td><input type="text" name="fin-gross_margin" value="' + escHtml(empty(f.gross_margin)) + '"></td>' +
|
||
'<td><input type="text" name="fin-net_margin" value="' + escHtml(empty(f.net_margin)) + '"></td>' +
|
||
'<td><input type="text" name="fin-debt_ratio" value="' + escHtml(empty(f.debt_ratio)) + '"></td>' +
|
||
'<td><input type="text" name="fin-financial_report_url" value="' + escHtml(empty(f.financial_report_url)) + '"></td>' +
|
||
'<td><input type="text" name="fin-data_source" value="' + escHtml(empty(f.data_source)) + '" placeholder="手动录入"></td>' +
|
||
'<td><button type="button" class="btn btn-sm btn-danger" onclick="$(this).closest(\'tr\').remove()">移除</button></td>' +
|
||
'</tr>';
|
||
}
|
||
|
||
/** 资质认证行模板(含级别/颁证机构) */
|
||
function certRowHtml(ct, certTypes) {
|
||
ct = ct || {};
|
||
var opts = '<option value="">请选择认证类型</option>';
|
||
certTypes.forEach(function (t) {
|
||
opts += '<option value="' + t.id + '"' + (String(t.id) === String(ct.certification_type_id) ? ' selected' : '') + '>' + escHtml(t.name) + '</option>';
|
||
});
|
||
return '<div class="cert-row">' +
|
||
'<select name="cert-type">' + opts + '</select>' +
|
||
'<input type="text" name="cert-number" placeholder="证书编号" value="' + escHtml(ct.certificate_number || '') + '">' +
|
||
'<input type="text" name="cert-level" placeholder="级别" value="' + escHtml(ct.level || '') + '">' +
|
||
'<input type="text" name="cert-issuer" placeholder="颁证机构" value="' + escHtml(ct.issuing_authority || '') + '">' +
|
||
'<input type="date" name="cert-issue" value="' + escHtml(ct.issue_date || '') + '">' +
|
||
'<input type="date" name="cert-expiry" value="' + escHtml(ct.expiry_date || '') + '">' +
|
||
'<button type="button" class="btn btn-sm btn-danger" onclick="$(this).closest(\'.cert-row\').remove()">删除</button>' +
|
||
'</div>';
|
||
}
|
||
|
||
/** 联系方式行模板(企业 social_accounts) */
|
||
function accountRowHtml(a) {
|
||
a = a || {};
|
||
var empty = function (v) { return (v === null || v === undefined) ? '' : v; };
|
||
var platOpts = ['', '官网', '微信公众号', '微信', '微博', '抖音', '快手', 'B站', '小红书', '领英', 'Facebook', 'Twitter/X', 'YouTube', 'Instagram', '其他'];
|
||
var platHtml = '';
|
||
platOpts.forEach(function (p) {
|
||
platHtml += '<option value="' + escHtml(p) + '"' + (String(p) === String(a.platform || '') ? ' selected' : '') + '>' + (p || '平台') + '</option>';
|
||
});
|
||
return '<div class="account-row">' +
|
||
'<select name="acc-platform">' + platHtml + '</select>' +
|
||
'<input type="text" name="acc-account" placeholder="账号名称/ID" value="' + escHtml(empty(a.account_id)) + '">' +
|
||
'<input type="text" name="acc-url" placeholder="主页链接" value="' + escHtml(empty(a.profile_url)) + '">' +
|
||
'<input type="text" name="acc-remark" placeholder="备注" value="' + escHtml(empty(a.remark)) + '">' +
|
||
'<select name="acc-active" title="状态"><option value="1"' + (a.is_active !== 0 ? ' selected' : '') + '>启用</option>' +
|
||
'<option value="0"' + (a.is_active === 0 ? ' selected' : '') + '>停用</option></select>' +
|
||
'<label title="常用" style="font-size:12px;color:#5a6472;white-space:nowrap;"><input type="checkbox" name="acc-defult"' + (a.is_defult ? ' checked' : '') + '> 常用</label>' +
|
||
'<button type="button" class="btn btn-sm btn-danger" onclick="$(this).closest(\'.account-row\').remove()">删除</button>' +
|
||
'</div>';
|
||
}
|
||
|
||
function roleOptions(sel) {
|
||
var opts = ['', 'manufacturer', 'integrator', 'distributor', 'brand_operator', 'others'];
|
||
var labels = { 'manufacturer': '生产型', 'integrator': '集成商', 'distributor': '代理商', 'brand_operator': '品牌运营', 'others': '其他' };
|
||
var html = '<option value="">-</option>';
|
||
opts.forEach(function (v) {
|
||
if (v === '') return;
|
||
html += '<option value="' + v + '"' + (sel === v ? ' selected' : '') + '>' + (labels[v] || v) + '</option>';
|
||
});
|
||
return html;
|
||
}
|
||
|
||
/* ---------- 导入 ---------- */
|
||
$('#btn-import').on('click', function () {
|
||
triggerFileInput('.csv', function (file) {
|
||
var fd = new FormData();
|
||
fd.append('file', file);
|
||
httpPost('company/import.php', fd, true).then(function (d) {
|
||
Dialog.alert('导入结果:成功 ' + d.inserted + ' 条,失败 ' + d.failed + ' 条', function () {
|
||
loadList(1);
|
||
});
|
||
});
|
||
});
|
||
});
|
||
|
||
/* ---------- 导出(仅导出勾选的企业,未勾选弹窗提醒) ---------- */
|
||
$('#btn-export').on('click', function () {
|
||
var ids = [];
|
||
$('.row-check:checked').each(function () { ids.push($(this).val()); });
|
||
if (!ids.length) {
|
||
layer.alert('请先选择需要导出的企业数据', { icon: 2, title: '提示' });
|
||
return;
|
||
}
|
||
download('company/export.php', { ids: ids.join(',') });
|
||
});
|
||
|
||
/* ---------- 详情 ---------- */
|
||
window.viewCompany = function (id) {
|
||
httpGet('company/detail.php', { id: id }).then(function (d) {
|
||
var c = d.company;
|
||
// 联系方式列表(social_accounts 中属于该公司的记录,仅展示)
|
||
var accountsHtml = '';
|
||
(d.accounts || []).forEach(function (a) {
|
||
var tag = '';
|
||
if (a.is_defult) tag = ' <span class="tag">常用</span>';
|
||
else if (a.is_primary) tag = ' <span class="tag">默认</span>';
|
||
accountsHtml += '<tr>' +
|
||
'<td>' + escHtml(a.platform || '-') + '</td>' +
|
||
'<td>' + escHtml(a.account_id || '-') + '</td>' +
|
||
'<td>' + (a.profile_url ? '<a href="' + escHtml(a.profile_url) + '" target="_blank">打开</a>' : '-') + '</td>' +
|
||
'<td>' + escHtml(a.remark || '-') + '</td>' +
|
||
'<td>' + (a.is_active ? '<span class="tag tag-green">启用</span>' : '<span class="tag tag-gray">停用</span>') + tag + '</td>' +
|
||
'</tr>';
|
||
});
|
||
var accountsSection = accountsHtml
|
||
? '<table class="grid" style="font-size:12px;"><tr><th>平台</th><th>账号/号码</th><th>主页链接</th><th>备注</th><th>状态</th></tr>' + accountsHtml + '</table>'
|
||
: '<div style="font-size:13px;color:#b6bfcc;">暂无联系方式</div>';
|
||
|
||
var html =
|
||
'<div style="padding:18px 22px;">' +
|
||
' <h3 style="margin-bottom:14px;">' + escHtml(c.name_zh || c.name_en || '企业 #' + c.id) + '</h3>' +
|
||
' <div class="detail-grid" style="display:grid;grid-template-columns:1fr 1fr;gap:8px 24px;font-size:13px;">' +
|
||
detailRow('企业名称', c.name_zh) + detailRow('企业类型', c.legal_form) +
|
||
detailRow('业务角色', c.business_role) + detailRow('国家/地区', c.country) +
|
||
detailRow('注册号', c.registration_number) + detailRow('地址', c.address) +
|
||
detailRow('法定代表人', c.legal_representative) + detailRow('行业', c.industry) +
|
||
detailRow('行业细分', c.industry_subdivision) + detailRow('官网', c.website) +
|
||
detailRow('注册资本', c.registered_capital) + detailRow('成立日期', c.established_date) +
|
||
detailRow('员工数', c.latest_employee_count) + detailRow('年营收', c.latest_annual_revenue) +
|
||
detailRow('是否上市', c.is_listed ? '是' : '否') + detailRow('股票代码', c.stock_code) +
|
||
detailRow('来源渠道', c.source_channel) + detailRow('来源详情', c.source_detail) +
|
||
'</div>' +
|
||
' <h4 style="margin:16px 0 8px;">经营范围</h4><div style="font-size:13px;color:#5a6472;">' + escHtml(c.business_scope || '-') + '</div>' +
|
||
' <h4 style="margin:16px 0 8px;">联系方式</h4>' + accountsSection +
|
||
'</div>';
|
||
Dialog.open({ title: '企业详情', area: ['820px', 'auto'], content: html, btn: ['关闭'] });
|
||
});
|
||
};
|
||
|
||
function detailRow(label, val) {
|
||
return '<div><b>' + label + ':</b>' + escHtml(val || '-') + '</div>';
|
||
}
|
||
|
||
/* ---------- 员工列表弹窗(按公司查看员工,分页 + 姓名/职级筛选) ---------- */
|
||
var empCompanyId = 0;
|
||
var empPage = 1;
|
||
|
||
window.viewEmployees = function (companyId) {
|
||
empCompanyId = companyId;
|
||
empPage = 1;
|
||
var content =
|
||
'<div style="padding:14px 18px 6px;overflow:hidden;height:330px;">' +
|
||
' <div class="toolbar" style="margin-bottom:10px;">' +
|
||
' <input type="text" id="emp-keyword" placeholder="姓名关键词" style="width:140px;">' +
|
||
' <select id="emp-level" style="width:130px;"><option value="">全部职级</option></select>' +
|
||
' <span style="font-size:13px;color:#5a6472;">状态:</span>' +
|
||
' <label style="font-size:13px;color:#5a6472;"><input type="checkbox" id="emp-cur" checked> 在岗</label>' +
|
||
' <label style="font-size:13px;color:#5a6472;"><input type="checkbox" id="emp-off" checked> 离职</label>' +
|
||
' <button class="btn btn-primary btn-sm" id="emp-search">搜索</button>' +
|
||
' <button class="btn btn-sm" id="emp-reset">重置</button>' +
|
||
' </div>' +
|
||
' <div class="table-wrap"><table class="grid" style="font-size:13px;">' +
|
||
' <thead><tr><th>姓名</th><th>联系方式</th><th>邮箱</th><th>职级</th><th>部门</th><th>岗位</th><th>入职日期</th><th>状态</th></tr></thead>' +
|
||
' <tbody id="emp-tbody"></tbody>' +
|
||
' </table></div>' +
|
||
' <div class="pagination" id="emp-pagination"></div>' +
|
||
'</div>';
|
||
var idx = Dialog.open({ title: '员工列表', area: ['920px', 'auto'], content: content, btn: ['关闭'] });
|
||
window.__empDialogIdx = idx;
|
||
|
||
loadEmployees(1);
|
||
|
||
$('#emp-search').on('click', function () { loadEmployees(1); });
|
||
$('#emp-reset').on('click', function () {
|
||
$('#emp-keyword').val('');
|
||
$('#emp-level').val('');
|
||
$('#emp-cur').prop('checked', true);
|
||
$('#emp-off').prop('checked', true);
|
||
loadEmployees(1);
|
||
});
|
||
};
|
||
|
||
function loadEmployees(page) {
|
||
empPage = page;
|
||
var params = { company_id: empCompanyId, page: page, limit: 5 };
|
||
var kw = $.trim($('#emp-keyword').val());
|
||
var lv = $('#emp-level').val();
|
||
var cur = $('#emp-cur').prop('checked');
|
||
var off = $('#emp-off').prop('checked');
|
||
if (kw) params.keyword = kw;
|
||
if (lv) params.job_level = lv;
|
||
// 状态筛选:只勾一项则按该项过滤;都不勾视为全部
|
||
if (cur && !off) params.is_current = 1;
|
||
else if (!cur && off) params.is_current = 0;
|
||
|
||
httpGet('company/employees.php', params).then(function (data) {
|
||
var rows = data.list || [];
|
||
var html = '';
|
||
rows.forEach(function (r) {
|
||
html += '<tr>' +
|
||
'<td>' + escHtml(r.full_name) + '</td>' +
|
||
'<td>' + escHtml(r.phone || '-') + '</td>' +
|
||
'<td>' + escHtml(r.email || '-') + '</td>' +
|
||
'<td>' + escHtml(r.job_level || '-') + '</td>' +
|
||
'<td>' + escHtml(r.department || '-') + '</td>' +
|
||
'<td>' + escHtml(r.position || '-') + '</td>' +
|
||
'<td>' + escHtml(r.start_date || '-') + '</td>' +
|
||
'<td>' + (r.is_current ? '<span class="tag tag-green">在职</span>' : '<span class="tag tag-gray">离职</span>') + '</td>' +
|
||
'</tr>';
|
||
});
|
||
if (!rows.length) {
|
||
html = '<tr><td colspan="8" class="empty-tip" style="padding:30px 0;">暂无员工</td></tr>';
|
||
}
|
||
$('#emp-tbody').html(html);
|
||
|
||
// 职级下拉(仅首次填充)
|
||
var $lv = $('#emp-level');
|
||
if ($lv.find('option').length <= 1) {
|
||
var optHtml = '<option value="">全部职级</option>';
|
||
(data.levels || []).forEach(function (l) {
|
||
optHtml += '<option value="' + escHtml(l) + '">' + escHtml(l) + '</option>';
|
||
});
|
||
$lv.html(optHtml);
|
||
}
|
||
|
||
renderPagination($('#emp-pagination'), data, loadEmployees);
|
||
});
|
||
}
|
||
|
||
/* ---------- 产品弹窗(产品品类/基本定位/包含系列/状态/更新日期 + 新增产品) ---------- */
|
||
var prodCompanyId = 0;
|
||
|
||
window.viewProducts = function (companyId) {
|
||
prodCompanyId = companyId;
|
||
var content =
|
||
'<div style="padding:14px 18px 6px;overflow:hidden;height:360px;">' +
|
||
' <div class="toolbar" style="margin-bottom:10px;">' +
|
||
' <span style="font-size:13px;color:#5a6472;">共 <b id="prod-total">0</b> 条产品记录</span>' +
|
||
' <span class="spacer"></span>' +
|
||
' <button class="btn btn-success btn-sm" id="btn-add-product">+ 新增产品</button>' +
|
||
' </div>' +
|
||
' <div class="table-wrap"><table class="grid" style="font-size:13px;">' +
|
||
' <thead><tr><th>产品品类</th><th>基本定位</th><th>包含系列</th><th>状态</th><th>更新日期</th><th>参数</th></tr></thead>' +
|
||
' <tbody id="prod-tbody"></tbody>' +
|
||
' </table></div>' +
|
||
' <div class="pagination" id="prod-pagination"></div>' +
|
||
'</div>';
|
||
Dialog.open({ title: '产品列表', area: ['860px', 'auto'], content: content, btn: ['关闭'] });
|
||
loadProducts(1);
|
||
|
||
$('#btn-add-product').on('click', function () { openProductForm(null); });
|
||
};
|
||
|
||
function loadProducts(page) {
|
||
httpGet('company/products.php', { company_id: prodCompanyId, page: page, limit: 5 }).then(function (data) {
|
||
$('#prod-total').text(data.total);
|
||
var rows = data.list || [];
|
||
var html = '';
|
||
rows.forEach(function (r) {
|
||
var attrHtml = (r.attrs && r.attrs.length)
|
||
? r.attrs.map(function (a) { return '<div>' + escHtml(a.attr_name) + (a.unit ? '(' + escHtml(a.unit) + ')' : '') + ':' + escHtml(a.value) + '</div>'; }).join('')
|
||
: '<span style="color:#b6bfcc;">-</span>';
|
||
html += '<tr>' +
|
||
'<td>' + escHtml(r.category_name) + '</td>' +
|
||
'<td title="' + escHtml(r.positioning || '') + '">' + escHtml((r.positioning || '-').substring(0, 24)) + '</td>' +
|
||
'<td>' + escHtml(r.series || '-') + '</td>' +
|
||
'<td>' + (r.is_active ? '<span class="tag tag-green">在产</span>' : '<span class="tag tag-gray">停产</span>') + '</td>' +
|
||
'<td>' + fmtDate(r.updated_at || r.created_at) + '</td>' +
|
||
'<td style="font-size:12px;">' + attrHtml + '</td>' +
|
||
'</tr>';
|
||
});
|
||
if (!rows.length) {
|
||
html = '<tr><td colspan="6" class="empty-tip" style="padding:30px 0;">暂无产品,点击右上角「+ 新增产品」添加</td></tr>';
|
||
}
|
||
$('#prod-tbody').html(html);
|
||
renderPagination($('#prod-pagination'), data, loadProducts);
|
||
});
|
||
}
|
||
|
||
/** 新增产品弹窗(含 EAV 参数,按企业所属行业加载参数属性定义) */
|
||
function openProductForm() {
|
||
// 获取企业行业
|
||
httpGet('company/detail.php', { id: prodCompanyId }).then(function (d) {
|
||
var industry = (d.company && d.company.industry) || '';
|
||
var content =
|
||
'<form id="product-form" style="padding:18px 22px 4px;">' +
|
||
'<div class="form-grid">' +
|
||
' <div class="form-item"><label>产品品类<span class="req">*</span></label><input type="text" name="category_name" placeholder="如:工业机器人、手机"></div>' +
|
||
' <div class="form-item"><label>包含系列</label><input type="text" name="series" placeholder="如:SUV、Gen 13"></div>' +
|
||
' <div class="form-item"><label>状态</label><select name="is_active"><option value="1" selected>在产</option><option value="0">停产</option></select></div>' +
|
||
' <div class="form-item"><label>是否核心</label><select name="is_core"><option value="0" selected>否</option><option value="1">是</option></select></div>' +
|
||
' <div class="form-item full"><label>产品基本定位</label><textarea name="positioning" placeholder="介绍这一款产品的商业定位"></textarea></div>' +
|
||
' <div class="form-item full"><label>品类描述</label><textarea name="category_description" placeholder="选填"></textarea></div>' +
|
||
'</div>' +
|
||
'<div id="product-attr-box" style="margin-top:6px;' + (industry ? '' : 'display:none;') + '">' +
|
||
' <b style="font-size:13px;color:#1e2a3a;">产品参数' + (industry ? '(' + escHtml(industry) + ')' : '') + '</b>' +
|
||
' <div id="product-attr-rows" style="margin-top:8px;"></div>' +
|
||
'</div>' +
|
||
'<div class="dialog-footer"><button type="button" class="btn" id="prod-form-cancel">取消</button>' +
|
||
'<button type="submit" class="btn btn-primary">保存</button></div>' +
|
||
'</form>';
|
||
|
||
var idx = Dialog.open({
|
||
title: '新增产品',
|
||
area: ['640px', 'auto'],
|
||
content: content,
|
||
btn: false
|
||
});
|
||
|
||
$('#prod-form-cancel').on('click', function () { Dialog.close(idx); });
|
||
|
||
// 加载该行业参数属性定义(EAV)
|
||
if (industry) {
|
||
httpGet('company/product_attrs.php', { industry: industry }).then(function (rd) {
|
||
var attrs = rd.attrs || [];
|
||
var html = '';
|
||
attrs.forEach(function (a) {
|
||
html += '<div class="form-item" style="width:calc(50% - 10px);display:inline-block;margin-right:10px;">' +
|
||
'<label>' + escHtml(a.attr_name) + (a.unit ? '(' + escHtml(a.unit) + ')' : '') + '</label>' +
|
||
'<input type="text" data-attr-id="' + a.id + '" data-attr-type="' + escHtml(a.attr_type) + '" placeholder="' +
|
||
(a.attr_type === 'boolean' ? '是/否' : a.attr_type === 'date' ? 'YYYY-MM-DD' : '') + '"></div>';
|
||
});
|
||
if (!attrs.length) {
|
||
html = '<div style="font-size:12px;color:#b6bfcc;">该行业暂无参数属性定义(可在 company_products_attr 表中维护)</div>';
|
||
}
|
||
$('#product-attr-rows').html(html);
|
||
}).catch(function () {});
|
||
}
|
||
|
||
$('#product-form').on('submit', function (e) {
|
||
e.preventDefault();
|
||
var data = {};
|
||
$(this).find('input, select, textarea').each(function () {
|
||
var name = $(this).attr('name');
|
||
if (name) data[name] = $(this).val();
|
||
});
|
||
if (!data.category_name) { Dialog.error('产品品类为必填项'); return; }
|
||
|
||
// 收集 EAV 参数值
|
||
var attrs = [];
|
||
$('#product-attr-rows input[data-attr-id]').each(function () {
|
||
var $this = $(this);
|
||
var val = $.trim($this.val());
|
||
if (!val) return;
|
||
attrs.push({ attr_id: $this.data('attr-id'), value: val });
|
||
});
|
||
data.company_id = prodCompanyId;
|
||
data.attrs = JSON.stringify(attrs);
|
||
|
||
httpPost('company/product_add.php', data).then(function () {
|
||
Dialog.success('新增成功', function () {
|
||
Dialog.close(idx);
|
||
loadProducts(1);
|
||
});
|
||
});
|
||
});
|
||
});
|
||
}
|
||
|
||
/* ---------- 官媒弹窗(该公司媒体清单 + 新增官媒) ---------- */
|
||
var mediaCompanyId = 0;
|
||
|
||
window.viewOfficialMedia = function (companyId) {
|
||
mediaCompanyId = companyId;
|
||
var content =
|
||
'<div style="padding:14px 18px 6px;overflow:hidden;height:360px;">' +
|
||
' <div class="toolbar" style="margin-bottom:10px;">' +
|
||
' <span style="font-size:13px;color:#5a6472;">共 <b id="media-total">0</b> 条官媒记录</span>' +
|
||
' <span class="spacer"></span>' +
|
||
' <button class="btn btn-success btn-sm" id="btn-add-media">+ 新增官媒</button>' +
|
||
' </div>' +
|
||
' <div class="table-wrap"><table class="grid" style="font-size:13px;">' +
|
||
' <thead><tr><th>平台</th><th>账号名称</th><th>ID</th><th>主页链接</th><th>状态</th><th>更新日期</th></tr></thead>' +
|
||
' <tbody id="media-tbody"></tbody>' +
|
||
' </table></div>' +
|
||
' <div class="pagination" id="media-pagination"></div>' +
|
||
'</div>';
|
||
Dialog.open({ title: '官媒列表', area: ['820px', 'auto'], content: content, btn: ['关闭'] });
|
||
loadOfficialMedia(1);
|
||
|
||
$('#btn-add-media').on('click', function () { openOfficialMediaForm(); });
|
||
};
|
||
|
||
function loadOfficialMedia(page) {
|
||
httpGet('company/official_media_list.php', { company_id: mediaCompanyId, page: page, limit: 5 }).then(function (data) {
|
||
$('#media-total').text(data.total);
|
||
var rows = data.list || [];
|
||
var html = '';
|
||
rows.forEach(function (r) {
|
||
html += '<tr>' +
|
||
'<td>' + escHtml(r.platform || '-') + '</td>' +
|
||
'<td>' + escHtml(r.account_id || '-') + '</td>' +
|
||
'<td>' + r.id + '</td>' +
|
||
'<td>' + (r.profile_url ? '<a href="' + escHtml(r.profile_url) + '" target="_blank">打开</a>' : '-') + '</td>' +
|
||
'<td>' + (r.is_active ? '<span class="tag tag-green">启用</span>' : '<span class="tag tag-gray">停用</span>') + '</td>' +
|
||
'<td>' + fmtDate(r.updated_at || r.created_at) + '</td>' +
|
||
'</tr>';
|
||
});
|
||
if (!rows.length) {
|
||
html = '<tr><td colspan="6" class="empty-tip" style="padding:30px 0;">暂无官媒,点击右上角「+ 新增官媒」添加</td></tr>';
|
||
}
|
||
$('#media-tbody').html(html);
|
||
renderPagination($('#media-pagination'), data, loadOfficialMedia);
|
||
});
|
||
}
|
||
|
||
/** 产业链(占位:入口先行,功能后续迭代实现) */
|
||
window.viewIndustryChain = function (companyId) {
|
||
Dialog.alert('产业链功能建设中,敬请期待');
|
||
};
|
||
|
||
/** 新增官媒弹窗 */
|
||
function openOfficialMediaForm() {
|
||
var content =
|
||
'<form id="media-form" style="padding:18px 22px 4px;">' +
|
||
'<div class="form-grid">' +
|
||
' <div class="form-item"><label>平台<span class="req">*</span></label><input type="text" name="platform" placeholder="如:微博、微信公众号、抖音"></div>' +
|
||
' <div class="form-item"><label>账号名称<span class="req">*</span></label><input type="text" name="account_id" placeholder="账号名称/ID"></div>' +
|
||
' <div class="form-item full"><label>主页链接</label><input type="text" name="profile_url" placeholder="https://..."></div>' +
|
||
' <div class="form-item full"><label>备注</label><input type="text" name="remark"></div>' +
|
||
' <div class="form-item"><label>状态</label><select name="is_active"><option value="1" selected>启用</option><option value="0">停用</option></select></div>' +
|
||
' <div class="form-item"><label>是否常用</label><select name="is_defult"><option value="0" selected>否</option><option value="1">是</option></select></div>' +
|
||
'</div>' +
|
||
'<div class="dialog-footer"><button type="button" class="btn" id="media-form-cancel">取消</button>' +
|
||
'<button type="submit" class="btn btn-primary">保存</button></div>' +
|
||
'</form>';
|
||
|
||
var idx = Dialog.open({
|
||
title: '新增官媒',
|
||
area: ['620px', 'auto'],
|
||
content: content,
|
||
btn: false
|
||
});
|
||
|
||
$('#media-form-cancel').on('click', function () { Dialog.close(idx); });
|
||
|
||
$('#media-form').on('submit', function (e) {
|
||
e.preventDefault();
|
||
var data = {};
|
||
$(this).find('input, select').each(function () {
|
||
var name = $(this).attr('name');
|
||
if (name) data[name] = $(this).val();
|
||
});
|
||
if (!data.platform || !data.account_id) { Dialog.error('平台与账号名称为必填项'); return; }
|
||
data.company_id = mediaCompanyId;
|
||
|
||
httpPost('company/official_media_add.php', data).then(function () {
|
||
Dialog.success('新增成功', function () {
|
||
Dialog.close(idx);
|
||
loadOfficialMedia(1);
|
||
});
|
||
});
|
||
});
|
||
}
|
||
});
|