信用档案法人节点新增相关企业信息;新增经营异常、严重违法信息
This commit is contained in:
parent
88b2ec4dcb
commit
edac46da8c
|
|
@ -231,6 +231,21 @@ export function getCreditArchive(params) {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据人员姓名/证件号查询其担任的相关企业(信用档案图谱三级节点扩展)
|
||||
* @param {Object} params
|
||||
* @param {string} params.name 姓名(必填)
|
||||
* @param {string} [params.cerno] 证件号(可选,精确匹配)
|
||||
* @param {string} [params.excludePripid] 排除的主体pripid(可选)
|
||||
*/
|
||||
export function getPersonRelatedEnts(params) {
|
||||
return request({
|
||||
url: '/eBaseinfo/getPersonRelatedEnts',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 信用修复预警统计
|
||||
* @param data
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
style="margin-left: 12px;"
|
||||
@click="resetGraph"
|
||||
>重置图谱</el-button>
|
||||
<span class="toolbar-tip">提示:点击一级分支可展开/收起明细,单分支最多展示 {{ maxNodes }} 个节点</span>
|
||||
<span class="toolbar-tip">提示:点击一级分支可展开/收起明细,法定代表人二级节点再次点击可查看相关企业,单分支最多展示 {{ maxNodes }} 个节点</span>
|
||||
</div>
|
||||
<div ref="graph" class="graph-container" />
|
||||
|
||||
|
|
@ -24,17 +24,16 @@
|
|||
v-for="(value, key) in detailData"
|
||||
:key="key"
|
||||
:label="fieldLabel(key)"
|
||||
>{{ value || '—' }}</el-descriptions-item>
|
||||
>{{ formatDetailValue(key, value) }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getCreditArchive } from '@/api/comprehensive'
|
||||
import { getCreditArchive, getPersonRelatedEnts } from '@/api/comprehensive'
|
||||
|
||||
const MAX_NODES = 20
|
||||
// 固定查询前一年:如当前 2026 年则查 2025 年
|
||||
const DEFAULT_YEAR = new Date().getFullYear() - 1
|
||||
|
||||
const FIELD_LABEL_MAP = {
|
||||
|
|
@ -51,16 +50,31 @@ const FIELD_LABEL_MAP = {
|
|||
email: '电子邮箱',
|
||||
invid: '股东ID',
|
||||
outinvid: '对外投资ID',
|
||||
lmid: '联络员ID'
|
||||
lmid: '联络员ID',
|
||||
specause: '列入原因',
|
||||
abntime: '列入日期',
|
||||
decorg: '列入决定机关',
|
||||
remexcpres: '移出原因',
|
||||
remdate: '移出日期',
|
||||
status: '状态'
|
||||
}
|
||||
|
||||
const BRANCH_DEFS = [
|
||||
{ key: 'shareholders', label: '股东信息', color: '#5470c6' },
|
||||
{ key: 'legalPersons', label: '法定代表人', color: '#91cc75' },
|
||||
{ key: 'investments', label: '对外投资', color: '#fac858' },
|
||||
{ key: 'contacts', label: '联络人', color: '#ee6666' }
|
||||
{ key: 'contacts', label: '联络人', color: '#ee6666' },
|
||||
{ key: 'abnormals', label: '经营异常名录', color: '#fc8452' },
|
||||
{ key: 'seriousIllegals', label: '严重违法失信', color: '#ea4335' }
|
||||
]
|
||||
|
||||
const ROLE_LABEL_MAP = {
|
||||
LEGAL_PERSON: '法人',
|
||||
PRINCIPAL_PERSON: '主要人员',
|
||||
SHAREHOLDER: '股东',
|
||||
OPERATOR: '经营者'
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'CreditArchive',
|
||||
props: {
|
||||
|
|
@ -83,12 +97,16 @@ export default {
|
|||
shareholders: [],
|
||||
legalPersons: [],
|
||||
investments: [],
|
||||
contacts: []
|
||||
contacts: [],
|
||||
abnormals: [],
|
||||
seriousIllegals: []
|
||||
},
|
||||
truncated: {
|
||||
shareholders: false,
|
||||
investments: false,
|
||||
contacts: false
|
||||
contacts: false,
|
||||
abnormals: false,
|
||||
seriousIllegals: false
|
||||
},
|
||||
branches: BRANCH_DEFS,
|
||||
detailVisible: false,
|
||||
|
|
@ -111,6 +129,15 @@ export default {
|
|||
fieldLabel(key) {
|
||||
return FIELD_LABEL_MAP[key] || key
|
||||
},
|
||||
formatDetailValue(key, value) {
|
||||
if (key === 'status') {
|
||||
return value === 'IN' ? '在列' : value === 'OUT' ? '已移出' : (value || '—')
|
||||
}
|
||||
if (key === 'lerepsign') {
|
||||
return value === '1' ? '法定代表人' : (value || '—')
|
||||
}
|
||||
return value || '—'
|
||||
},
|
||||
async loadData() {
|
||||
if (!this.pripid) return
|
||||
this.loading = true
|
||||
|
|
@ -124,9 +151,17 @@ export default {
|
|||
shareholders: data.shareholders || [],
|
||||
legalPersons: data.legalPersons || [],
|
||||
investments: data.investments || [],
|
||||
contacts: data.contacts || []
|
||||
contacts: data.contacts || [],
|
||||
abnormals: data.abnormals || [],
|
||||
seriousIllegals: data.seriousIllegals || []
|
||||
}
|
||||
this.truncated = data.truncated || {
|
||||
shareholders: false,
|
||||
investments: false,
|
||||
contacts: false,
|
||||
abnormals: false,
|
||||
seriousIllegals: false
|
||||
}
|
||||
this.truncated = data.truncated || { shareholders: false, investments: false, contacts: false }
|
||||
this.$nextTick(() => this.renderGraph())
|
||||
} catch (e) {
|
||||
this.$message.error('信用档案数据加载失败')
|
||||
|
|
@ -153,13 +188,23 @@ export default {
|
|||
itemStyle: { color: '#409EFF' },
|
||||
label: { fontWeight: 'bold' }
|
||||
}
|
||||
const branchNodes = this.branches.map((b, i) => ({
|
||||
const branchNodes = this.branches.map((b, i) => {
|
||||
const list = this.archiveData[b.key] || []
|
||||
const count = list.length
|
||||
const isTruncated = this.truncated[b.key]
|
||||
const label = count === 0
|
||||
? b.label
|
||||
: isTruncated
|
||||
? `${b.label} (${MAX_NODES}+)`
|
||||
: `${b.label} (${count})`
|
||||
return {
|
||||
id: b.key,
|
||||
name: `${b.label} (${(this.archiveData[b.key] || []).length})`,
|
||||
name: label,
|
||||
symbolSize: 50,
|
||||
category: i + 1,
|
||||
itemStyle: { color: b.color }
|
||||
}))
|
||||
}
|
||||
})
|
||||
const branchLinks = this.branches.map(b => ({
|
||||
source: 'center',
|
||||
target: b.key,
|
||||
|
|
@ -169,10 +214,7 @@ export default {
|
|||
this.chart.setOption({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: params => {
|
||||
if (params.dataType === 'edge') return ''
|
||||
return params.name
|
||||
}
|
||||
formatter: params => this.formatTooltip(params)
|
||||
},
|
||||
legend: [{
|
||||
data: this.branches.map(b => b.label),
|
||||
|
|
@ -195,22 +237,81 @@ export default {
|
|||
}]
|
||||
}, true)
|
||||
},
|
||||
formatTooltip(params) {
|
||||
if (params.dataType === 'edge') return ''
|
||||
const data = params.data
|
||||
if (!data) return params.name
|
||||
|
||||
// 三级相关企业节点
|
||||
if (data.targetPripid && data.rawData) {
|
||||
const ent = data.rawData
|
||||
const roles = (ent.roles || []).map(r => ROLE_LABEL_MAP[r] || r).join('、')
|
||||
return `${ent.entName || '—'}<br/>角色:${roles}<br/>经营状态:${ent.regstateCn || '—'}`
|
||||
}
|
||||
|
||||
// 二级节点 - 经营异常 / 严重违法失信
|
||||
if (data.rawData && data.parentKey) {
|
||||
const raw = data.rawData
|
||||
const branchKey = data.parentKey
|
||||
if (branchKey === 'abnormals' || branchKey === 'seriousIllegals') {
|
||||
const lines = []
|
||||
if (raw.specause) lines.push(`列入原因:${raw.specause}`)
|
||||
if (raw.abntime) lines.push(`列入日期:${raw.abntime}`)
|
||||
if (raw.decorg) lines.push(`列入决定机关:${raw.decorg}`)
|
||||
if (raw.status === 'OUT') {
|
||||
if (raw.remexcpres) lines.push(`移出原因:${raw.remexcpres}`)
|
||||
if (raw.remdate) lines.push(`移出日期:${raw.remdate}`)
|
||||
}
|
||||
lines.push(`状态:${raw.status === 'IN' ? '在列' : '已移出'}`)
|
||||
return lines.join('<br/>')
|
||||
}
|
||||
}
|
||||
|
||||
return params.name
|
||||
},
|
||||
handleNodeClick(params) {
|
||||
// 点击中心节点 / 边 → 忽略
|
||||
if (!params.data || params.dataType === 'edge') return
|
||||
const branch = this.branches.find(b => b.key === params.data.id)
|
||||
const data = params.data
|
||||
|
||||
// 一级分支 → toggleBranch
|
||||
const branch = this.branches.find(b => b.key === data.id)
|
||||
if (branch) {
|
||||
this.toggleBranch(branch)
|
||||
return
|
||||
}
|
||||
// 二级节点点击 → 弹出明细
|
||||
if (params.data.rawData) {
|
||||
const parentKey = String(params.data.id).split('-')[0]
|
||||
|
||||
// 三级相关企业节点 → 新 tab 跳转企业详情
|
||||
if (String(data.id).startsWith('rel-')) {
|
||||
const pripid = data.targetPripid
|
||||
if (pripid) {
|
||||
const routeUrl = this.$router.resolve({
|
||||
path: '/comprehensive/details',
|
||||
query: { pripid }
|
||||
}).href
|
||||
window.open(routeUrl, '_blank')
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 二级节点
|
||||
if (data.rawData) {
|
||||
const parentKey = String(data.id).split('-')[0]
|
||||
|
||||
// 法定代表人二级节点 → 扩展三级「相关企业」
|
||||
if (parentKey === 'legalPersons') {
|
||||
this.togglePersonRelatedEnts(data)
|
||||
return
|
||||
}
|
||||
|
||||
// 经营异常 / 严重违法 / 其他 → 弹详情
|
||||
this.openDetailDialog(parentKey, data.rawData)
|
||||
}
|
||||
},
|
||||
openDetailDialog(parentKey, rawData) {
|
||||
const parentBranch = this.branches.find(b => b.key === parentKey)
|
||||
this.detailTitle = parentBranch ? `${parentBranch.label}详情` : '详情'
|
||||
this.detailData = params.data.rawData
|
||||
this.detailData = rawData
|
||||
this.detailVisible = true
|
||||
}
|
||||
},
|
||||
toggleBranch(branch) {
|
||||
const list = this.archiveData[branch.key] || []
|
||||
|
|
@ -224,26 +325,35 @@ export default {
|
|||
const hasChild = series.data.some(n => String(n.id).startsWith(prefix))
|
||||
|
||||
if (hasChild) {
|
||||
// 收起
|
||||
series.data = series.data.filter(n => !String(n.id).startsWith(prefix))
|
||||
series.links = series.links.filter(l => !String(l.target).startsWith(prefix))
|
||||
// 收起(同时收起该分支下的三级 rel- 节点)
|
||||
series.data = series.data.filter(n => {
|
||||
const id = String(n.id)
|
||||
return !id.startsWith(prefix) && !(n._parentPrefix && n._parentPrefix.startsWith(prefix))
|
||||
})
|
||||
series.links = series.links.filter(l => {
|
||||
const target = String(l.target)
|
||||
return !target.startsWith(prefix) && !(l._parentPrefix && l._parentPrefix.startsWith(prefix))
|
||||
})
|
||||
} else {
|
||||
// Q11:单分支最多展开 MAX_NODES 个节点,超出部分显示"更多..."
|
||||
const displayList = list.slice(0, MAX_NODES)
|
||||
const categoryIndex = this.branches.indexOf(branch) + 1
|
||||
displayList.forEach((item, i) => {
|
||||
const nodeId = `${branch.key}-${i}`
|
||||
series.data.push({
|
||||
const nodeData = {
|
||||
id: nodeId,
|
||||
name: this.getNodeName(branch.key, item),
|
||||
name: this.getNodeName(branch.key, item, i),
|
||||
symbolSize: 30,
|
||||
category: categoryIndex,
|
||||
itemStyle: { color: branch.color, opacity: 0.7 },
|
||||
rawData: item
|
||||
})
|
||||
itemStyle: {
|
||||
color: branch.color,
|
||||
opacity: this.getAbnormalOpacity(branch.key, item)
|
||||
},
|
||||
rawData: item,
|
||||
parentKey: branch.key
|
||||
}
|
||||
series.data.push(nodeData)
|
||||
series.links.push({ source: branch.key, target: nodeId })
|
||||
})
|
||||
// 后端返回的截断标志或前端二次判断
|
||||
const isTruncated = this.truncated[branch.key] || list.length > MAX_NODES
|
||||
if (isTruncated) {
|
||||
const moreId = `${branch.key}-more`
|
||||
|
|
@ -259,11 +369,130 @@ export default {
|
|||
}
|
||||
this.chart.setOption(option, true)
|
||||
},
|
||||
getNodeName(key, item) {
|
||||
getNodeName(key, item, index) {
|
||||
if (key === 'investments') return item.entName || '—'
|
||||
if (key === 'shareholders') return item.name || '—'
|
||||
if (key === 'contacts') return item.name || '—'
|
||||
if (key === 'legalPersons') return item.name || '—'
|
||||
if (key === 'abnormals') {
|
||||
return this.getAbnormalNodeName(item, '经营异常', index)
|
||||
}
|
||||
if (key === 'seriousIllegals') {
|
||||
return this.getAbnormalNodeName(item, '严重违法', index)
|
||||
}
|
||||
return item.name || '—'
|
||||
},
|
||||
getAbnormalNodeName(item, fallbackPrefix, index) {
|
||||
const cause = item.specause
|
||||
const time = item.abntime
|
||||
if (cause) {
|
||||
const truncatedCause = cause.length > 10 ? cause.substring(0, 10) + '...' : cause
|
||||
if (time) {
|
||||
const dateStr = this.formatDateToYM(time)
|
||||
return `${truncatedCause} (${dateStr})`
|
||||
}
|
||||
return truncatedCause
|
||||
}
|
||||
return `${fallbackPrefix} ${index != null ? index + 1 : ''}`.trim()
|
||||
},
|
||||
getAbnormalOpacity(branchKey, item) {
|
||||
if (branchKey === 'abnormals' || branchKey === 'seriousIllegals') {
|
||||
return item.status === 'OUT' ? 0.4 : 0.7
|
||||
}
|
||||
return 0.7
|
||||
},
|
||||
formatDateToYM(dateVal) {
|
||||
if (!dateVal) return ''
|
||||
const d = new Date(dateVal)
|
||||
if (isNaN(d.getTime())) return String(dateVal).substring(0, 7)
|
||||
const y = d.getFullYear()
|
||||
const m = String(d.getMonth() + 1).padStart(2, '0')
|
||||
return `${y}-${m}`
|
||||
},
|
||||
async togglePersonRelatedEnts(personNode) {
|
||||
const prefix = `rel-${personNode.id}-`
|
||||
const option = this.chart.getOption()
|
||||
const series = option.series[0]
|
||||
const hasChild = series.data.some(n => String(n.id).startsWith(prefix))
|
||||
|
||||
// 已展开 → 收起
|
||||
if (hasChild) {
|
||||
series.data = series.data.filter(n => !String(n.id).startsWith(prefix))
|
||||
series.links = series.links.filter(l => !String(l.target).startsWith(prefix))
|
||||
this.chart.setOption(option, true)
|
||||
return
|
||||
}
|
||||
|
||||
// 调接口
|
||||
const person = personNode.rawData
|
||||
this.loading = true
|
||||
try {
|
||||
const res = await getPersonRelatedEnts({
|
||||
name: person.name,
|
||||
cerno: person.cerno,
|
||||
excludePripid: this.pripid
|
||||
})
|
||||
const data = (res && res.data) || res || {}
|
||||
const list = data.ents || []
|
||||
if (!list.length) {
|
||||
this.$message.info('未查询到该人员的其他相关企业')
|
||||
return
|
||||
}
|
||||
const truncated = !!data.truncated
|
||||
const displayList = list.slice(0, MAX_NODES)
|
||||
const categoryIndex = this.branches.findIndex(b => b.key === 'legalPersons') + 1
|
||||
displayList.forEach((ent, i) => {
|
||||
const nodeId = `${prefix}${i}`
|
||||
const nodeData = {
|
||||
id: nodeId,
|
||||
name: this.buildRelatedEntLabel(ent),
|
||||
symbolSize: 22,
|
||||
category: categoryIndex,
|
||||
itemStyle: { color: '#91cc75', opacity: 0.5 },
|
||||
targetPripid: ent.pripid,
|
||||
rawData: ent,
|
||||
_parentPrefix: 'legalPersons-'
|
||||
}
|
||||
series.data.push(nodeData)
|
||||
series.links.push({
|
||||
source: personNode.id,
|
||||
target: nodeId,
|
||||
lineStyle: { type: 'dashed', color: '#91cc75' },
|
||||
_parentPrefix: 'legalPersons-'
|
||||
})
|
||||
})
|
||||
if (truncated) {
|
||||
const moreId = `${prefix}more`
|
||||
series.data.push({
|
||||
id: moreId,
|
||||
name: `更多... (共 ${displayList.length}+ 项)`,
|
||||
symbolSize: 20,
|
||||
category: categoryIndex,
|
||||
itemStyle: { color: '#91cc75', opacity: 0.3 },
|
||||
_parentPrefix: 'legalPersons-'
|
||||
})
|
||||
series.links.push({
|
||||
source: personNode.id,
|
||||
target: moreId,
|
||||
lineStyle: { type: 'dashed' },
|
||||
_parentPrefix: 'legalPersons-'
|
||||
})
|
||||
}
|
||||
this.chart.setOption(option, true)
|
||||
} catch (e) {
|
||||
this.$message.error('查询相关企业失败')
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
buildRelatedEntLabel(ent) {
|
||||
const name = ent.entName || '—'
|
||||
const roles = (ent.roles || []).map(r => ROLE_LABEL_MAP[r] || r)
|
||||
if (roles.length) {
|
||||
return `${name}(${roles.join('/')})`
|
||||
}
|
||||
return name
|
||||
},
|
||||
resetGraph() {
|
||||
this.renderGraph()
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue