6403 changed files with 2255146 additions and 357 deletions
@ -0,0 +1,182 @@ |
|||
1_产品概述.md |
|||
1_模块说明.md |
|||
2_流程说明.md |
|||
2_需求矩阵.md |
|||
3_修订记录.md |
|||
3_功能说明.md |
|||
4_功能结构.md |
|||
4_快速检索栏及相关菜单说明.md |
|||
5_业务流程.md |
|||
6_非功能需求.md |
|||
7_项目干系人.md |
|||
A0-1-1登录页.md |
|||
A0-3-1个人信息.md |
|||
A1-1_工作台.md |
|||
A1-2_消息中心.md |
|||
A1X-1-1_新增工作计划.md |
|||
A1X-1-2_填写今日工作.md |
|||
A1X-1-3_工作计划详情.md |
|||
A1X-1_工作计划_工作日历.md |
|||
A1X-2_工作计划_计划管理.md |
|||
A1X-3_工作计划_出差与拜访.md |
|||
A2-1-1-1线索详情.md |
|||
A2-1-1线索公海(分屏视图).md |
|||
A2-1-1线索公海(列表视图).md |
|||
A2-1-2-1线索详情.md |
|||
A2-1-2-2新增线索.md |
|||
A2-1-2-3编辑线索.md |
|||
A2-1-2-4导入线索.md |
|||
A2-1-2-4导入线索_717.md |
|||
A2-1-2我的线索.md |
|||
A2-1-3我的关注.md |
|||
A2-1-4-1新增线索.md |
|||
A2-1-4-2导入线索717.md |
|||
A2-1-4-2导入线索(草稿).md |
|||
A2-1-4线索管理.md |
|||
A2-1-5线索设置.md |
|||
A3-0-1-1_商机详情.md |
|||
A3-0-1_最近访问列表.md |
|||
A3-1-1-1-1_(个人)商机详情_概览.md |
|||
A3-1-1-1-2(个人)商机详情_客户信息.md |
|||
A3-1-1-1-3-1_编辑方案卡.md |
|||
A3-1-1-1-3(个人)商机详情_方案卡.md |
|||
A3-1-1-1-4(个人)商机详情_现场勘察.md |
|||
A3-1-1-1-5(个人)商机详情_相关附件.md |
|||
A3-1-1-1-6(个人)商机详情_跟进记录.md |
|||
A3-1-1-1-7(个人)商机详情_工作计划.md |
|||
A3-1-1-1-8(个人)商机详情_团队成员.md |
|||
A3-1-1-1-9(个人)商机详情_操作日志.md |
|||
A3-1-1-2-10_新增现场勘察.md |
|||
A3-1-1-2-1_新增_编辑商机.md |
|||
A3-1-1-2-2_写跟进.md |
|||
A3-1-1-2-3_新增方案卡.md |
|||
A3-1-1-2-4_添加关联客户.md |
|||
A3-1-1-2-5_推送方案.md |
|||
A3-1-1-2-6_暂缓商机.md |
|||
A3-1-1-2-7_抛公海.md |
|||
A3-1-1-2-8_添加团队成员&一键拉群.md |
|||
A3-1-1-2-9_关闭商机.md |
|||
A3-1-1_销售机会列表.md |
|||
A3-2-1-1-1_督办功能.md |
|||
A3-2-1-1_(管理)商机详情.md |
|||
A3-2-1_全部销售机会管理列表.md |
|||
A3-3-1-1-2_领取.md |
|||
A3-3-1-1-3_关注.md |
|||
A3-3-1-1-4_分配.md |
|||
A3-3-1-1_(公海)商机详情.md |
|||
A3-3-1_商机公海列表.md |
|||
A3-4-1-1_商机阶段设置_(新增_编辑页)_(1).md |
|||
A3-4-2_方案卡模板_(1).md |
|||
A3-4-3_方案推送规则_(1).md |
|||
A4-1-1_客户公海列表(列表视图).md |
|||
A4-1-2_客户公海列表(分屏视图).md |
|||
A4-2-1_客户总览列表(分屏视图).md |
|||
A4-2-1_客户总览列表(列表视图).md |
|||
A4-2-1_客户总览列表(卡片视图).md |
|||
A4-3-1_我的客户列表(分屏视图).md |
|||
A4-3-1_我的客户列表(列表视图).md |
|||
A4-3-1_我的客户列表(卡片视图).md |
|||
A4-3-2_客户导入.md |
|||
A4-3-3-1_新增客户信息.md |
|||
A4-3-3-2_编辑客户信息.md |
|||
A4-3-3-3_添加联系人.md |
|||
A4-3-3-4_OCR快捷新增.md |
|||
A4-4-10_编辑战略协议.md |
|||
A4-4-1_客户详情(客户信息).md |
|||
A4-4-1_客户详情(已归档客户).md |
|||
A4-4-1_客户详情(已被合并客户).md |
|||
A4-4-2_客户详情(联系人).md |
|||
A4-4-3_客户详情(跟进记录).md |
|||
A4-4-4_客户详情(关联商机).md |
|||
A4-4-5_客户详情(关联项目).md |
|||
A4-4-6_客户详情(战略协议).md |
|||
A4-4-7_客户详情(团队成员).md |
|||
A4-4-8_客户详情(操作日志).md |
|||
A4-4-9_新增战略协议.md |
|||
A4-5-1_联系人列表(分屏视图).md |
|||
A4-5-1_联系人列表(列表视图).md |
|||
A4-5-2_新增联系人.md |
|||
A4-5-3_编辑联系人.md |
|||
A4-5-4_联系人导入.md |
|||
A4-5-5_联系人详情(联系人信息).md |
|||
A4-5-6_联系人详情(操作日志).md |
|||
A4-6-1_客户查重(卡片视图).md |
|||
A4-6-2_客户查重(列表视图).md |
|||
A4-6-3_客户合并.md |
|||
A4-7-1_客户交割(发起交接).md |
|||
A4-7-2_客户交割(客户分配).md |
|||
A4-7-3_客户交割(交接记录).md |
|||
A4-7-4_交接记录详情.md |
|||
A5-1-1-1b_项目详情(处理冲突-异地).md |
|||
A5-1-1-1_项目详情(处理冲突-本地).md |
|||
A5-1-1-2_项目详情(方案设计).md |
|||
A5-1-1-3_项目详情(商务报价).md |
|||
A5-1-1-4_项目详情(招投标准备).md |
|||
A5-1-1-5_项目详情(商务跟进).md |
|||
A5-1-1-5_项目详情(赢单_输单).md |
|||
A5-1-1-6_项目详情(结项).md |
|||
A5-1-1-7_项目详情(已关闭).md |
|||
A5-1-1_项目管理(分屏视图).md |
|||
A5-1-1_项目管理(列表视图).md |
|||
A5-1-1_项目管理(看板视图).md |
|||
A5-1-2-1_我的项目(分屏视图).md |
|||
A5-1-2-1_我的项目(看板视图).md |
|||
A5-1-2-2_项目详情(页签详情与操作).md |
|||
A5-1-2_我的项目.md |
|||
A5-1-4_项目统计.md |
|||
A6-1-1_运营看板.md |
|||
A6-1-2_客户看板.md |
|||
A6-1-3_营销看板.md |
|||
A7-1-1_用户列表.md |
|||
A7-1-2_同步任务.md |
|||
A7-2-1_角色管理.md |
|||
A7-2-2_权限点管理.md |
|||
A7-2-2_编辑角色(基本信息).md |
|||
A7-2-3-1_新建_编辑共享规则.md |
|||
A7-2-3-2_共享规则详情.md |
|||
A7-2-3_数据共享.md |
|||
A7-2-3_编辑角色(功能权限).md |
|||
A7-2-4_编辑角色(数据范围_).md |
|||
A7-3-1_线索规则.md |
|||
A7-3-2-1-1_商机阶段设置_(详情页).md |
|||
A7-3-2-1-2_商机阶段设置_(新增_编辑页).md |
|||
A7-3-2-1_商机阶段设置(列表页).md |
|||
A7-3-2-2-1_方案卡模板(详情页).md |
|||
A7-3-2-2-2_方案卡模板(新增_编辑页).md |
|||
A7-3-2-2_方案卡模板(列表页).md |
|||
A7-3-2-3-1_方案推送规则_(详情页).md |
|||
A7-3-2-3-2_方案推送规则_(新增_编辑页).md |
|||
A7-3-2-3_方案推送规则(列表页).md |
|||
A7-3-2-4-1_查重规则(详情页).md |
|||
A7-3-2-4-2_查重规则(新增_编辑页).md |
|||
A7-3-2-4_项目查重规则.md |
|||
A7-3-2-5-1_公海与提醒规则(详情页).md |
|||
A7-3-2-5-2_公海与提醒规则(新增_编辑页).md |
|||
A7-3-2-5_公海与提醒规则(列表页).md |
|||
A7-3-2-6_商机相关字典.md |
|||
A7-3-3-1_客户管理设置(超期未跟进提醒).md |
|||
A7-3-3-2_客户管理设置(客户查重设置).md |
|||
A7-3-4_项目规则.md |
|||
A7-4-1_用户操作日志.md |
|||
A7-4-2_登录日志.md |
|||
A7-4-3_批量操作日志.md |
|||
A7-5-1_数据字典.md |
|||
修订记录.md |
|||
全局说明.md |
|||
分页.md |
|||
加载中.md |
|||
对话框_弹窗.md |
|||
导入.md |
|||
布局说明.md |
|||
异常页面.md |
|||
搜索.md |
|||
数据空态.md |
|||
模块流程.md |
|||
母版.md |
|||
气泡提示.md |
|||
表单.md |
|||
表格.md |
|||
输入框.md |
|||
通知提示.md |
|||
键盘.md |
|||
(历史存档)首页.md |
|||
@ -0,0 +1,42 @@ |
|||
# -*- coding: utf-8 -*- |
|||
"""查 head 原文 + 浏览器 styleSheets 加载情况""" |
|||
import io, sys, time |
|||
from pathlib import Path |
|||
|
|||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') |
|||
|
|||
P = Path(r'e:\code\crm-backend-matt\.scratch\a7-parity\pages\a7-3-1_线索规则') |
|||
h = (P / 'a7-3-1_线索规则.html').read_text(encoding='utf-8', errors='replace') |
|||
head = h[:h.find('</head>') + 7] |
|||
print('=== raw <link lines in head ===') |
|||
for line in head.splitlines(): |
|||
if 'link' in line.lower() or 'stylesheet' in line.lower(): |
|||
print(line.strip()[:200]) |
|||
|
|||
html_path = P / 'a7-3-1_线索规则.html' |
|||
url = 'file:///' + str(html_path).replace('\\', '/') |
|||
from playwright.sync_api import sync_playwright |
|||
with sync_playwright() as p: |
|||
browser = p.chromium.launch() |
|||
ctx = browser.new_context(viewport={'width': 1600, 'height': 900}) |
|||
ctx.add_init_script("window.lanhu_Axure_Mapping_Data = function(d){ return d; };") |
|||
page = ctx.new_page() |
|||
page.goto(url, wait_until='domcontentloaded', timeout=20000) |
|||
time.sleep(2) |
|||
info = page.evaluate("""() => ({ |
|||
sheets: [...document.styleSheets].map(s => { |
|||
let n = -1; try { n = s.cssRules.length } catch(e) { n = 'ERR:' + e.message } |
|||
return {href: (s.href||'inline').split('/').pop(), rules: n}; |
|||
}), |
|||
u3: (() => { const el = document.getElementById('u3'); |
|||
if (!el) return 'no u3'; |
|||
const cs = getComputedStyle(el); |
|||
return {pos: cs.position, left: cs.left, top: cs.top, w: cs.width, h: cs.height}; })(), |
|||
u3img: (() => { const el = document.getElementById('u3_img'); |
|||
if (!el) return 'none'; |
|||
const cs = getComputedStyle(el); |
|||
return {w: cs.width, h: cs.height, display: cs.display, src: el.src.slice(-30)}; })(), |
|||
})""") |
|||
for k, v in info.items(): |
|||
print(k, ':', v) |
|||
browser.close() |
|||
@ -0,0 +1,50 @@ |
|||
# -*- coding: utf-8 -*- |
|||
"""带恒等注入的深度诊断:console 全量 + 主容器隐藏点""" |
|||
import io, sys, time |
|||
from pathlib import Path |
|||
|
|||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') |
|||
sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8') |
|||
|
|||
html_path = Path(r'e:\code\crm-backend-matt\.scratch\a7-parity\pages\a7-3-1_线索规则\a7-3-1_线索规则.html') |
|||
url = 'file:///' + str(html_path).replace('\\', '/') |
|||
|
|||
from playwright.sync_api import sync_playwright |
|||
|
|||
with sync_playwright() as p: |
|||
browser = p.chromium.launch() |
|||
ctx = browser.new_context(viewport={'width': 1600, 'height': 900}) |
|||
ctx.add_init_script( |
|||
"window.lanhu_Axure_Mapping_Data = function(d){ return d; };") |
|||
page = ctx.new_page() |
|||
page.on('console', lambda m: print(f'[c.{m.type}] {m.text[:220]}')) |
|||
page.on('pageerror', lambda e: print(f'[pageerror] {str(e)[:300]}')) |
|||
page.on('requestfailed', lambda r: print(f'[reqfail] {r.url[:130]} {r.failure}')) |
|||
page.goto(url, wait_until='domcontentloaded', timeout=20000) |
|||
time.sleep(3) |
|||
page.evaluate("() => { try { window.dispatchEvent(new Event('load')); } catch(e){} }") |
|||
time.sleep(2) |
|||
info = page.evaluate("""() => { |
|||
const body = document.body; |
|||
const kids = [...body.children].slice(0, 12).map(el => { |
|||
const cs = getComputedStyle(el); |
|||
return {tag: el.tagName, id: el.id, cls: (el.className||'').toString().slice(0,40), |
|||
display: cs.display, vis: cs.visibility, h: cs.height, |
|||
inlineStyle: (el.getAttribute('style')||'').slice(0,120)}; |
|||
}); |
|||
const bcs = getComputedStyle(body); |
|||
return {bodyLen: body.innerHTML.length, |
|||
uDivs: document.querySelectorAll('[id^=u]').length, |
|||
bodyOverflow: bcs.overflow, bodyH: bcs.height, bodyVis: bcs.visibility, |
|||
scrollH: document.documentElement.scrollHeight, |
|||
kids}; |
|||
}""") |
|||
print('=== DOM state ===') |
|||
for k, v in info.items(): |
|||
if k == 'kids': |
|||
print('body children:') |
|||
for c in v: |
|||
print(' ', c) |
|||
else: |
|||
print(k, ':', v) |
|||
browser.close() |
|||
@ -0,0 +1,36 @@ |
|||
# -*- coding: utf-8 -*- |
|||
"""对比:不 dispatch load 直接截图,看页面是否可见""" |
|||
import io, sys, time |
|||
from pathlib import Path |
|||
|
|||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') |
|||
P = Path(r'e:\code\crm-backend-matt\.scratch\a7-parity\pages\a7-3-1_线索规则') |
|||
url = 'file:///' + str((P / 'a7-3-1_线索规则.html')).replace('\\', '/') |
|||
|
|||
from playwright.sync_api import sync_playwright |
|||
with sync_playwright() as p: |
|||
browser = p.chromium.launch() |
|||
ctx = browser.new_context(viewport={'width': 1600, 'height': 900}) |
|||
ctx.add_init_script("window.lanhu_Axure_Mapping_Data = function(d){ return d; };") |
|||
page = ctx.new_page() |
|||
page.goto(url, wait_until='domcontentloaded', timeout=20000) |
|||
time.sleep(3) |
|||
dim = page.evaluate("() => [document.documentElement.scrollWidth, document.documentElement.scrollHeight]") |
|||
print('dim (no dispatch):', dim) |
|||
vis = page.evaluate("""() => { |
|||
const b = document.getElementById('base'); |
|||
const cs = getComputedStyle(b); |
|||
// 沿祖先链找隐藏者 |
|||
let el = b, chain = []; |
|||
while (el && el !== document.documentElement) { |
|||
const s = getComputedStyle(el); |
|||
if (s.display === 'none' || s.visibility === 'hidden' || s.opacity === '0') |
|||
chain.push({id: el.id || el.tagName, display: s.display, vis: s.visibility, op: s.opacity}); |
|||
el = el.parentElement; |
|||
} |
|||
return {baseVis: cs.visibility, baseDisp: cs.display, hiddenChain: chain}; |
|||
}""") |
|||
print('visibility chain:', vis) |
|||
page.screenshot(path=str(P.parent.parent / 'shots' / 'debug-nodispatch.png'), full_page=True) |
|||
print('saved debug-nodispatch.png') |
|||
browser.close() |
|||
@ -0,0 +1,46 @@ |
|||
# deploy-bruno-t12.ps1 - ticket 12g: copy staging tree into docs repo (conflict precheck + copy + verify + ledger) |
|||
$ErrorActionPreference = 'Stop' |
|||
$src = 'e:\code\crm-backend-matt\.scratch\a7-parity\t12-bru' |
|||
$dst = 'E:\code\crm-api-docs' |
|||
|
|||
$files = Get-ChildItem -LiteralPath $src -Recurse -File -Filter '*.bru' |
|||
Write-Output ("source files: {0}" -f $files.Count) |
|||
|
|||
# 1. conflict precheck: any same-name file already in docs repo -> abort (never overwrite silently) |
|||
$conflicts = @() |
|||
foreach ($f in $files) { |
|||
$rel = $f.FullName.Substring($src.Length).TrimStart('\') |
|||
$target = Join-Path $dst $rel |
|||
if (Test-Path -LiteralPath $target) { $conflicts += $rel } |
|||
} |
|||
if ($conflicts.Count -gt 0) { |
|||
Write-Output ("ABORT: {0} target files already exist:" -f $conflicts.Count) |
|||
$conflicts | ForEach-Object { Write-Output (" {0}" -f $_) } |
|||
exit 1 |
|||
} |
|||
|
|||
# 2. copy (create parent dirs as needed) |
|||
$copied = 0 |
|||
foreach ($f in $files) { |
|||
$rel = $f.FullName.Substring($src.Length).TrimStart('\') |
|||
$target = Join-Path $dst $rel |
|||
$targetDir = Split-Path -Parent $target |
|||
if (-not (Test-Path -LiteralPath $targetDir)) { |
|||
New-Item -ItemType Directory -Path $targetDir -Force | Out-Null |
|||
} |
|||
Copy-Item -LiteralPath $f.FullName -Destination $target -Force |
|||
$copied++ |
|||
} |
|||
|
|||
# 3. verify: exists + byte size matches source |
|||
$errors = @() |
|||
foreach ($f in $files) { |
|||
$rel = $f.FullName.Substring($src.Length).TrimStart('\') |
|||
$target = Join-Path $dst $rel |
|||
if (-not (Test-Path -LiteralPath $target)) { $errors += ("missing: {0}" -f $rel); continue } |
|||
if ((Get-Item -LiteralPath $target).Length -ne $f.Length) { $errors += ("size-mismatch: {0}" -f $rel) } |
|||
} |
|||
|
|||
Write-Output ("copied={0} errors={1}" -f $copied, $errors.Count) |
|||
$errors | ForEach-Object { Write-Output ("ERR {0}" -f $_) } |
|||
if ($errors.Count -gt 0) { exit 1 } |
|||
@ -0,0 +1,27 @@ |
|||
# -*- coding: utf-8 -*- |
|||
"""dump #base 内部结构与 u div 样式来源""" |
|||
import io, sys |
|||
from pathlib import Path |
|||
|
|||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') |
|||
P = Path(r'e:\code\crm-backend-matt\.scratch\a7-parity\pages\a7-3-1_线索规则') |
|||
h = (P / 'a7-3-1_线索规则.html').read_text(encoding='utf-8', errors='replace') |
|||
i = h.find('<div id="base"') |
|||
print('=== base div innerHTML head ===') |
|||
print(h[i:i+1200]) |
|||
print() |
|||
print('=== first u div raw (in html) ===') |
|||
j = h.find('<div id="u3"') |
|||
print(h[j:j+400] if j >= 0 else 'u3 not found') |
|||
|
|||
# styles.css 是否被 html 引用 + 本地是否存在 |
|||
print() |
|||
print('=== css refs ===') |
|||
import re |
|||
for m in re.finditer(r'<link[^>]*href="([^"]+)"', h): |
|||
print(m.group(1)) |
|||
for rel in ['data/styles.css', 'resources/css/axure_rp_page.css']: |
|||
print(rel, 'exists:', (P / rel).exists()) |
|||
page_css = P / 'files' / 'a7-3-1_线索规则' / 'styles.css' |
|||
print('page styles.css exists:', page_css.exists(), |
|||
page_css.stat().st_size if page_css.exists() else 0) |
|||
@ -0,0 +1,134 @@ |
|||
// 拉取 A7 全部页面(正式树 31 + backup 数据共享 3)到本地可渲染目录结构。
|
|||
// 用法: node fetch-a7-pages.mjs [--only=a7-3-1]
|
|||
// 产物: .scratch/a7-parity/pages/<页面url去.html>/<原相对引用路径> (file:// 可直接渲染)
|
|||
// .scratch/a7-parity/oss-cache/<sign_md5> (全局去重缓存)
|
|||
import fs from 'fs'; |
|||
import path from 'path'; |
|||
import crypto from 'crypto'; |
|||
|
|||
const ROOT = 'e:/code/crm-backend-matt/.scratch/a7-parity'; |
|||
const LANHU = 'e:/code/crm-backend-matt/.scratch/lanhu-latest'; |
|||
const OSS = 'https://lanhu-axure-file.oss-cn-beijing.aliyuncs.com/'; |
|||
const UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'; |
|||
const CONCURRENCY = 8; |
|||
|
|||
const only = process.argv.find(a => a.startsWith('--only=')); |
|||
const onlyKey = only ? only.split('=')[1] : null; |
|||
|
|||
const doc = JSON.parse(fs.readFileSync(path.join(LANHU, 'axure-v29.json'), 'utf-8')); |
|||
const pages = doc.pages; |
|||
|
|||
// A7 页面(key = 页面名.html)
|
|||
const a7 = Object.entries(pages).filter(([k]) => k.toUpperCase().startsWith('A7')); |
|||
console.log(`A7 pages in manifest: ${a7.length}`); |
|||
if (onlyKey) { |
|||
const filtered = a7.filter(([k]) => k.includes(onlyKey)); |
|||
console.log(`--only=${onlyKey} matched: ${filtered.length}`); |
|||
if (filtered.length) { a7.length = 0; a7.push(...filtered); } |
|||
} |
|||
|
|||
const cacheDir = path.join(ROOT, 'oss-cache'); |
|||
fs.mkdirSync(cacheDir, { recursive: true }); |
|||
|
|||
const stats = { downloaded: 0, cacheHit: 0, failed: [], bytes: 0 }; |
|||
|
|||
async function fetchBuf(url, tries = 3) { |
|||
let lastErr; |
|||
for (let i = 0; i < tries; i++) { |
|||
try { |
|||
const res = await fetch(url, { headers: { 'User-Agent': UA } }); |
|||
if (!res.ok) throw new Error(`HTTP ${res.status} ${url}`); |
|||
return Buffer.from(await res.arrayBuffer()); |
|||
} catch (e) { |
|||
lastErr = e; |
|||
await new Promise(r => setTimeout(r, 800 * (i + 1))); |
|||
} |
|||
} |
|||
throw lastErr; |
|||
} |
|||
|
|||
// 下载 sign_md5 指向的 OSS 对象,优先 oss-cache
|
|||
async function fetchSigned(signMd5) { |
|||
const isUrl = signMd5.startsWith('http'); |
|||
const cacheKey = isUrl |
|||
? 'url_' + crypto.createHash('md5').update(signMd5).digest('hex') |
|||
: signMd5; |
|||
const cachePath = path.join(cacheDir, cacheKey); |
|||
if (fs.existsSync(cachePath)) { |
|||
stats.cacheHit++; |
|||
return fs.readFileSync(cachePath); |
|||
} |
|||
const url = isUrl ? signMd5 : OSS + signMd5; |
|||
const buf = await fetchBuf(url); |
|||
fs.writeFileSync(cachePath, buf); |
|||
stats.downloaded++; |
|||
stats.bytes += buf.length; |
|||
return buf; |
|||
} |
|||
|
|||
function safeName(relKey) { |
|||
// Windows 路径合法化(mapping key 已是解码后相对路径;替换非法字符)
|
|||
return relKey.split('/').map(seg => seg.replace(/[<>:"|?*]/g, '_')).join('/'); |
|||
} |
|||
|
|||
// 单页:下载 mapping → html(data-src→src)→ 全部资源
|
|||
async function fetchPage(key, entry) { |
|||
const pageDir = path.join(ROOT, 'pages', safeName(key.replace(/\.html$/, ''))); |
|||
const mappingBuf = await fetchSigned(entry.mapping_md5); |
|||
const mapping = JSON.parse(mappingBuf.toString('utf-8')); |
|||
|
|||
const jobs = []; // [relKey, signMd5]
|
|||
for (const [rel, v] of Object.entries(mapping.styles || {})) jobs.push([rel, v.sign_md5]); |
|||
for (const [rel, v] of Object.entries(mapping.scripts || {})) jobs.push([rel, v.sign_md5]); |
|||
for (const [rel, v] of Object.entries(mapping.images || {})) jobs.push([rel, v.sign_md5]); |
|||
if (mapping.dataJs?.src) jobs.push([mapping.dataJs.src, mapping.dataJs.sign_md5]); |
|||
if (mapping.html?.src) jobs.push([mapping.html.src, mapping.html.sign_md5]); |
|||
|
|||
let htmlBuf = null; |
|||
for (const [rel, sign] of jobs) { |
|||
const buf = await fetchSigned(sign); |
|||
const dest = path.join(pageDir, safeName(rel)); |
|||
fs.mkdirSync(path.dirname(dest), { recursive: true }); |
|||
if (rel === mapping.html.src) { |
|||
// 主页面 HTML:蓝湖的三处改写需还原 ——
|
|||
// ① <img src> 被改成 data-src 懒加载 → 还原为 src;
|
|||
// ② <link> 的 href 被改成 src(浏览器忽略 link 的 src,CSS 全部不加载)→ 还原为 href;
|
|||
// ③ <body style="display:none;opacity:0"> 防闪烁隐藏,解除逻辑在蓝湖 web 端注入代码 → 直接剥掉
|
|||
htmlBuf = buf.toString('utf-8') |
|||
.replace(/data-src="/g, 'src="') |
|||
.replace(/ rel="stylesheet" src="/g, ' rel="stylesheet" href="') |
|||
.replace(/<body[^>]*\sstyle="[^"]*display:\s*none[^"]*"[^>]*>/, '<body>') |
|||
.replace(/srcset="/g, 'data-srcset-disabled="'); |
|||
fs.writeFileSync(dest, htmlBuf, 'utf-8'); |
|||
} else { |
|||
fs.writeFileSync(dest, buf); |
|||
} |
|||
} |
|||
return { key, dir: pageDir, assets: jobs.length }; |
|||
} |
|||
|
|||
// 并发队列
|
|||
const queue = [...a7]; |
|||
const results = []; |
|||
async function worker(id) { |
|||
while (queue.length) { |
|||
const [key, entry] = queue.shift(); |
|||
try { |
|||
const r = await fetchPage(key, entry); |
|||
console.log(`[w${id}] OK ${key} (${r.assets} assets)`); |
|||
results.push({ key, ok: true, assets: r.assets }); |
|||
} catch (e) { |
|||
console.error(`[w${id}] FAIL ${key}: ${e.message}`); |
|||
results.push({ key, ok: false, error: e.message }); |
|||
stats.failed.push(key); |
|||
} |
|||
} |
|||
} |
|||
await Promise.all(Array.from({ length: CONCURRENCY }, (_, i) => worker(i))); |
|||
|
|||
console.log('=== summary ==='); |
|||
console.log(`pages ok: ${results.filter(r => r.ok).length}/${a7.length}`); |
|||
console.log(`oss downloads: ${stats.downloaded} (cache hits: ${stats.cacheHit}), ${(stats.bytes / 1048576).toFixed(1)} MB`); |
|||
if (stats.failed.length) console.log('failed:', stats.failed.join(', ')); |
|||
fs.writeFileSync(path.join(ROOT, 'fetch-a7.log'), |
|||
JSON.stringify({ results, stats }, null, 2)); |
|||
@ -0,0 +1,180 @@ |
|||
{ |
|||
"results": [ |
|||
{ |
|||
"key": "a7-2-2_编辑角色(基本信息).html", |
|||
"ok": true, |
|||
"assets": 59 |
|||
}, |
|||
{ |
|||
"key": "a7-1-2_同步任务.html", |
|||
"ok": true, |
|||
"assets": 88 |
|||
}, |
|||
{ |
|||
"key": "a7-3-1_线索规则.html", |
|||
"ok": true, |
|||
"assets": 232 |
|||
}, |
|||
{ |
|||
"key": "a7-3-2-1_商机阶段设置(列表页).html", |
|||
"ok": true, |
|||
"assets": 94 |
|||
}, |
|||
{ |
|||
"key": "a7-2-1_角色管理.html", |
|||
"ok": true, |
|||
"assets": 85 |
|||
}, |
|||
{ |
|||
"key": "a7-1-1_用户列表.html", |
|||
"ok": true, |
|||
"assets": 99 |
|||
}, |
|||
{ |
|||
"key": "a7-2-2_权限点管理.html", |
|||
"ok": true, |
|||
"assets": 107 |
|||
}, |
|||
{ |
|||
"key": "a7-2-4_编辑角色(数据范围_).html", |
|||
"ok": true, |
|||
"assets": 124 |
|||
}, |
|||
{ |
|||
"key": "a7-3-2-2-1_方案卡模板(详情页).html", |
|||
"ok": true, |
|||
"assets": 124 |
|||
}, |
|||
{ |
|||
"key": "a7-3-2-1-1_商机阶段设置__详情页_.html", |
|||
"ok": true, |
|||
"assets": 123 |
|||
}, |
|||
{ |
|||
"key": "a7-3-2-3_方案推送规则(列表页).html", |
|||
"ok": true, |
|||
"assets": 97 |
|||
}, |
|||
{ |
|||
"key": "a7-3-2-2-2_方案卡模板(新增_编辑页).html", |
|||
"ok": true, |
|||
"assets": 107 |
|||
}, |
|||
{ |
|||
"key": "a7-3-2-2_方案卡模板(列表页).html", |
|||
"ok": true, |
|||
"assets": 122 |
|||
}, |
|||
{ |
|||
"key": "a7-3-2-1-2_商机阶段设置__新增_编辑页_.html", |
|||
"ok": true, |
|||
"assets": 150 |
|||
}, |
|||
{ |
|||
"key": "a7-3-2-4_项目查重规则.html", |
|||
"ok": true, |
|||
"assets": 100 |
|||
}, |
|||
{ |
|||
"key": "a7-3-2-5_公海与提醒规则(列表页).html", |
|||
"ok": true, |
|||
"assets": 100 |
|||
}, |
|||
{ |
|||
"key": "a7-2-3_编辑角色(功能权限).html", |
|||
"ok": true, |
|||
"assets": 168 |
|||
}, |
|||
{ |
|||
"key": "a7-3-2-5-1_公海与提醒规则(详情页).html", |
|||
"ok": true, |
|||
"assets": 91 |
|||
}, |
|||
{ |
|||
"key": "a7-3-3-1_客户管理设置(超期未跟进提醒).html", |
|||
"ok": true, |
|||
"assets": 64 |
|||
}, |
|||
{ |
|||
"key": "a7-3-3-2_客户管理设置(客户查重设置).html", |
|||
"ok": true, |
|||
"assets": 75 |
|||
}, |
|||
{ |
|||
"key": "a7-3-2-5-2_公海与提醒规则(新增_编辑页).html", |
|||
"ok": true, |
|||
"assets": 93 |
|||
}, |
|||
{ |
|||
"key": "a7-3-2-3-1_方案推送规则__详情页_.html", |
|||
"ok": true, |
|||
"assets": 171 |
|||
}, |
|||
{ |
|||
"key": "a7-3-2-3-2_方案推送规则__新增_编辑页_.html", |
|||
"ok": true, |
|||
"assets": 199 |
|||
}, |
|||
{ |
|||
"key": "a7-4-1_用户操作日志.html", |
|||
"ok": true, |
|||
"assets": 104 |
|||
}, |
|||
{ |
|||
"key": "a7-4-2_登录日志.html", |
|||
"ok": true, |
|||
"assets": 98 |
|||
}, |
|||
{ |
|||
"key": "a7-3-2-6_商机相关字典.html", |
|||
"ok": true, |
|||
"assets": 184 |
|||
}, |
|||
{ |
|||
"key": "a7-2-3-1_新建_编辑共享规则.html", |
|||
"ok": true, |
|||
"assets": 44 |
|||
}, |
|||
{ |
|||
"key": "a7-2-3-2_共享规则详情.html", |
|||
"ok": true, |
|||
"assets": 71 |
|||
}, |
|||
{ |
|||
"key": "a7-3-4_项目规则.html", |
|||
"ok": true, |
|||
"assets": 131 |
|||
}, |
|||
{ |
|||
"key": "a7-2-3_数据共享.html", |
|||
"ok": true, |
|||
"assets": 88 |
|||
}, |
|||
{ |
|||
"key": "a7-3-2-4-1_查重规则(详情页).html", |
|||
"ok": true, |
|||
"assets": 239 |
|||
}, |
|||
{ |
|||
"key": "a7-3-2-4-2_查重规则(新增_编辑页).html", |
|||
"ok": true, |
|||
"assets": 247 |
|||
}, |
|||
{ |
|||
"key": "a7-4-3_批量操作日志.html", |
|||
"ok": true, |
|||
"assets": 137 |
|||
}, |
|||
{ |
|||
"key": "a7-5-1_数据字典.html", |
|||
"ok": true, |
|||
"assets": 213 |
|||
} |
|||
], |
|||
"stats": { |
|||
"downloaded": 1827, |
|||
"cacheHit": 2435, |
|||
"failed": [], |
|||
"bytes": 31334049 |
|||
} |
|||
} |
|||
@ -0,0 +1,92 @@ |
|||
# 票 11 bruno-sync tag 迁移收尾:写 11 个新 folder.bru + 删 49 个旧文件(删除前验证新文件已存在) |
|||
$ErrorActionPreference = 'Stop' |
|||
$root = 'E:\code\crm-api-docs' |
|||
$utf8 = New-Object System.Text.UTF8Encoding($false) |
|||
|
|||
# ---------- 1. folder.bru(name 与源码 tag 一致;seq 沿旧惯例) ---------- |
|||
$folders = @( |
|||
@('A7 后台管理\业务规则', '业务规则', 10), |
|||
@('A7 后台管理\业务规则\商机规则', '商机规则', 1), |
|||
@('A7 后台管理\业务规则\商机规则\商机阶段设置', '商机阶段设置', 10), |
|||
@('A7 后台管理\业务规则\商机规则\方案卡模板', '方案卡模板', 20), |
|||
@('A7 后台管理\业务规则\商机规则\公海与提醒', '公海与提醒', 30), |
|||
@('A7 后台管理\业务规则\商机规则\商机相关字典', '商机相关字典', 40), |
|||
@('A7 后台管理\业务规则\客户规则', '客户规则', 2), |
|||
@('A7 后台管理\系统设置', '系统设置', 11), |
|||
@('A7 后台管理\系统设置\数据字典', '数据字典', 1), |
|||
@('A7 后台管理\系统设置\数据字典\分组', '分组', 1), |
|||
@('A7 后台管理\系统设置\数据字典\字典项', '字典项', 2) |
|||
) |
|||
foreach ($f in $folders) { |
|||
$dir = Join-Path $root $f[0] |
|||
if (-not (Test-Path -LiteralPath $dir)) { throw ('missing dir: ' + $dir) } |
|||
$content = "meta {`n name: $($f[1])`n seq: $($f[2])`n}`n" |
|||
[IO.File]::WriteAllText((Join-Path $dir 'folder.bru'), $content, $utf8) |
|||
} |
|||
Write-Output ('folder.bru written: ' + $folders.Count) |
|||
|
|||
# ---------- 2. 删除旧文件(每个文件删除前验证对应新文件已存在,否则保留并报错) ---------- |
|||
$mig = @( |
|||
@('A7 后台管理\商机规则\阶段模板', 'A7 后台管理\业务规则\商机规则\商机阶段设置'), |
|||
@('A7 后台管理\商机规则\方案卡模板', 'A7 后台管理\业务规则\商机规则\方案卡模板'), |
|||
@('A7 后台管理\商机规则\公海规则', 'A7 后台管理\业务规则\商机规则\公海与提醒'), |
|||
@('A7 后台管理\客户管理设置\超期未跟进提醒', 'A7 后台管理\业务规则\客户规则\客户管理设置(超期未跟进提醒)'), |
|||
@('A7 后台管理\客户管理设置\查重设置', 'A7 后台管理\业务规则\客户规则\客户管理设置(客户查重设置)'), |
|||
@('A7 后台管理\数据字典\分组', 'A7 后台管理\系统设置\数据字典\分组'), |
|||
@('A7 后台管理\数据字典\字典项', 'A7 后台管理\系统设置\数据字典\字典项') |
|||
) |
|||
$deleted = 0 |
|||
$errors = @() |
|||
foreach ($m in $mig) { |
|||
$oldDir = Join-Path $root $m[0] |
|||
foreach ($fn in (Get-ChildItem -LiteralPath $oldDir -Filter '*.bru' | Select-Object -ExpandProperty Name)) { |
|||
$must = Join-Path (Join-Path $root $m[1]) $fn |
|||
if (-not (Test-Path -LiteralPath $must)) { |
|||
$errors += ('NEW MISSING, keep old: ' + $m[0] + '\' + $fn) |
|||
continue |
|||
} |
|||
Remove-Item -LiteralPath (Join-Path $oldDir $fn) -Force |
|||
$deleted++ |
|||
} |
|||
} |
|||
# 旧父目录 folder.bru(迁移后父目录空掉) |
|||
foreach ($pair in @( |
|||
@('A7 后台管理\商机规则\folder.bru', 'A7 后台管理\业务规则\商机规则\folder.bru'), |
|||
@('A7 后台管理\数据字典\folder.bru', 'A7 后台管理\系统设置\数据字典\folder.bru'))) { |
|||
if (Test-Path -LiteralPath (Join-Path $root $pair[1])) { |
|||
Remove-Item -LiteralPath (Join-Path $root $pair[0]) -Force |
|||
$deleted++ |
|||
} else { |
|||
$errors += ('NEW MISSING, keep old: ' + $pair[0]) |
|||
} |
|||
} |
|||
Write-Output ('deleted: ' + $deleted) |
|||
$errors | ForEach-Object { Write-Output (' ! ' + $_) } |
|||
|
|||
# ---------- 3. 清理空目录(仅删确认已空的目录) ---------- |
|||
foreach ($d in @('A7 后台管理\商机规则\阶段模板', 'A7 后台管理\商机规则\方案卡模板', 'A7 后台管理\商机规则\公海规则', |
|||
'A7 后台管理\商机规则', 'A7 后台管理\客户管理设置\超期未跟进提醒', 'A7 后台管理\客户管理设置\查重设置', |
|||
'A7 后台管理\客户管理设置', 'A7 后台管理\数据字典\分组', 'A7 后台管理\数据字典\字典项', 'A7 后台管理\数据字典')) { |
|||
$full = Join-Path $root $d |
|||
if ((Test-Path -LiteralPath $full) -and -not (Get-ChildItem -LiteralPath $full)) { |
|||
Remove-Item -LiteralPath $full -Force |
|||
Write-Output ('rmdir: ' + $d) |
|||
} |
|||
} |
|||
|
|||
# ---------- 4. 台账 ---------- |
|||
Write-Output '--- new structure ---' |
|||
foreach ($d in @('A7 后台管理\业务规则', 'A7 后台管理\业务规则\商机规则', 'A7 后台管理\业务规则\商机规则\商机阶段设置', |
|||
'A7 后台管理\业务规则\商机规则\方案卡模板', 'A7 后台管理\业务规则\商机规则\公海与提醒', |
|||
'A7 后台管理\业务规则\商机规则\商机相关字典', 'A7 后台管理\业务规则\客户规则', |
|||
'A7 后台管理\业务规则\客户规则\客户管理设置(超期未跟进提醒)', |
|||
'A7 后台管理\业务规则\客户规则\客户管理设置(客户查重设置)', |
|||
'A7 后台管理\系统设置', 'A7 后台管理\系统设置\数据字典', |
|||
'A7 后台管理\系统设置\数据字典\分组', 'A7 后台管理\系统设置\数据字典\字典项')) { |
|||
$full = Join-Path $root $d |
|||
$cnt = @(Get-ChildItem -LiteralPath $full).Count |
|||
Write-Output ('{0,2} files: {1}' -f $cnt, $d) |
|||
} |
|||
foreach ($d in @('A7 后台管理\商机规则', 'A7 后台管理\数据字典', 'A7 后台管理\客户管理设置')) { |
|||
Write-Output ('old {0} exists: {1}' -f $d, (Test-Path -LiteralPath (Join-Path $root $d))) |
|||
} |
|||
@ -0,0 +1,89 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# 票 11 bruno-sync tag 迁移收尾:写 11 个新 folder.bru + 删 49 个旧文件(删除前验证新文件已存在) |
|||
import os, sys |
|||
sys.stdout = open(sys.stdout.fileno(), 'w', encoding='utf-8', buffering=1) |
|||
|
|||
ROOT = r'E:\code\crm-api-docs' |
|||
|
|||
# ---------- 1. folder.bru(name 与源码 tag 一致;seq 沿旧惯例:商机规则下 10 步长,数据字典下 1/2) ---------- |
|||
FOLDERS = [ |
|||
(r'A7 后台管理\业务规则', '业务规则', 10), |
|||
(r'A7 后台管理\业务规则\商机规则', '商机规则', 1), |
|||
(r'A7 后台管理\业务规则\商机规则\商机阶段设置', '商机阶段设置', 10), |
|||
(r'A7 后台管理\业务规则\商机规则\方案卡模板', '方案卡模板', 20), |
|||
(r'A7 后台管理\业务规则\商机规则\公海与提醒', '公海与提醒', 30), |
|||
(r'A7 后台管理\业务规则\商机规则\商机相关字典', '商机相关字典', 40), |
|||
(r'A7 后台管理\业务规则\客户规则', '客户规则', 2), |
|||
(r'A7 后台管理\系统设置', '系统设置', 11), |
|||
(r'A7 后台管理\系统设置\数据字典', '数据字典', 1), |
|||
(r'A7 后台管理\系统设置\数据字典\分组', '分组', 1), |
|||
(r'A7 后台管理\系统设置\数据字典\字典项', '字典项', 2), |
|||
] |
|||
for rel, name, seq in FOLDERS: |
|||
full = os.path.join(ROOT, rel) |
|||
assert os.path.isdir(full), 'missing dir: ' + full |
|||
with open(os.path.join(full, 'folder.bru'), 'w', encoding='utf-8', newline='\n') as f: |
|||
f.write('meta {\n name: %s\n seq: %s\n}\n' % (name, seq)) |
|||
print('folder.bru written:', len(FOLDERS)) |
|||
|
|||
# ---------- 2. 删除旧文件(每个文件删除前验证对应新文件已存在,否则保留并报错) ---------- |
|||
MIG = [ |
|||
(r'A7 后台管理\商机规则\阶段模板', r'A7 后台管理\业务规则\商机规则\商机阶段设置'), |
|||
(r'A7 后台管理\商机规则\方案卡模板', r'A7 后台管理\业务规则\商机规则\方案卡模板'), |
|||
(r'A7 后台管理\商机规则\公海规则', r'A7 后台管理\业务规则\商机规则\公海与提醒'), |
|||
(r'A7 后台管理\客户管理设置\超期未跟进提醒', r'A7 后台管理\业务规则\客户规则\客户管理设置(超期未跟进提醒)'), |
|||
(r'A7 后台管理\客户管理设置\查重设置', r'A7 后台管理\业务规则\客户规则\客户管理设置(客户查重设置)'), |
|||
(r'A7 后台管理\数据字典\分组', r'A7 后台管理\系统设置\数据字典\分组'), |
|||
(r'A7 后台管理\数据字典\字典项', r'A7 后台管理\系统设置\数据字典\字典项'), |
|||
] |
|||
deleted, errors = [], [] |
|||
for old_dir, new_dir in MIG: |
|||
for fn in sorted(os.listdir(os.path.join(ROOT, old_dir))): |
|||
must = os.path.join(ROOT, new_dir, 'folder.bru' if fn == 'folder.bru' else fn) |
|||
if not os.path.exists(must): |
|||
errors.append('NEW MISSING, keep old: ' + old_dir + '\\' + fn) |
|||
continue |
|||
os.remove(os.path.join(ROOT, old_dir, fn)) |
|||
deleted.append(old_dir + '\\' + fn) |
|||
# 旧父目录 folder.bru(迁移后父目录空掉) |
|||
for old_f, new_f in [ |
|||
(r'A7 后台管理\商机规则\folder.bru', r'A7 后台管理\业务规则\商机规则\folder.bru'), |
|||
(r'A7 后台管理\数据字典\folder.bru', r'A7 后台管理\系统设置\数据字典\folder.bru'), |
|||
]: |
|||
if os.path.exists(os.path.join(ROOT, new_f)): |
|||
os.remove(os.path.join(ROOT, old_f)) |
|||
deleted.append(old_f) |
|||
else: |
|||
errors.append('NEW MISSING, keep old: ' + old_f) |
|||
print('deleted:', len(deleted)) |
|||
for d in deleted: |
|||
print(' -', d) |
|||
|
|||
# ---------- 3. 清理空目录(rmdir 仅删空目录,失败静默跳过) ---------- |
|||
for d in [r'A7 后台管理\商机规则\阶段模板', r'A7 后台管理\商机规则\方案卡模板', r'A7 后台管理\商机规则\公海规则', |
|||
r'A7 后台管理\商机规则', r'A7 后台管理\客户管理设置\超期未跟进提醒', r'A7 后台管理\客户管理设置\查重设置', |
|||
r'A7 后台管理\客户管理设置', r'A7 后台管理\数据字典\分组', r'A7 后台管理\数据字典\字典项', r'A7 后台管理\数据字典']: |
|||
try: |
|||
os.rmdir(os.path.join(ROOT, d)) |
|||
print('rmdir:', d) |
|||
except OSError: |
|||
pass |
|||
|
|||
# ---------- 4. 台账 ---------- |
|||
if errors: |
|||
print('ERRORS:') |
|||
for e in errors: |
|||
print(' !', e) |
|||
print('--- new structure ---') |
|||
for rel in [r'A7 后台管理\业务规则', r'A7 后台管理\业务规则\商机规则', r'A7 后台管理\业务规则\商机规则\商机阶段设置', |
|||
r'A7 后台管理\业务规则\商机规则\方案卡模板', r'A7 后台管理\业务规则\商机规则\公海与提醒', |
|||
r'A7 后台管理\业务规则\商机规则\商机相关字典', r'A7 后台管理\业务规则\客户规则', |
|||
r'A7 后台管理\业务规则\客户规则\客户管理设置(超期未跟进提醒)', |
|||
r'A7 后台管理\业务规则\客户规则\客户管理设置(客户查重设置)', |
|||
r'A7 后台管理\系统设置', r'A7 后台管理\系统设置\数据字典', |
|||
r'A7 后台管理\系统设置\数据字典\分组', r'A7 后台管理\系统设置\数据字典\字典项']: |
|||
full = os.path.join(ROOT, rel) |
|||
print('%2d files: %s' % (len(os.listdir(full)), rel)) |
|||
print('old 商机规则 exists:', os.path.exists(os.path.join(ROOT, r'A7 后台管理\商机规则'))) |
|||
print('old 数据字典 exists:', os.path.exists(os.path.join(ROOT, r'A7 后台管理\数据字典'))) |
|||
print('old 客户管理设置 exists:', os.path.exists(os.path.join(ROOT, r'A7 后台管理\客户管理设置'))) |
|||
@ -0,0 +1,35 @@ |
|||
# -*- coding: utf-8 -*- |
|||
"""定位 lanhu_Axure_Mapping_Data 的定义处""" |
|||
import io, sys, re |
|||
from pathlib import Path |
|||
|
|||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') |
|||
P = Path(r'e:\code\crm-backend-matt\.scratch\a7-parity\pages\a7-3-1_线索规则') |
|||
|
|||
# 1. data.js 头部 |
|||
dj = P / 'files' / 'a7-3-1_线索规则' / 'data.js' |
|||
print('=== data.js head ===', dj.exists(), dj.stat().st_size if dj.exists() else '') |
|||
print(dj.read_text(encoding='utf-8', errors='replace')[:200]) |
|||
|
|||
# 2. HTML 里的出现位置 |
|||
html = (P / 'a7-3-1_线索规则.html').read_text(encoding='utf-8', errors='replace') |
|||
print('=== occurrences in HTML ===') |
|||
for m in re.finditer(r'lanhu_Axure_Mapping_Data', html): |
|||
s = max(0, m.start() - 80) |
|||
print(repr(html[s:m.start() + 60]).replace('\\n', ' ')[:180]) |
|||
print('---') |
|||
|
|||
# 3. 全部已落盘 js 里搜定义 |
|||
print('=== search define in local js ===') |
|||
hits = [] |
|||
for f in P.rglob('*.js'): |
|||
try: |
|||
t = f.read_text(encoding='utf-8', errors='replace') |
|||
except Exception: |
|||
continue |
|||
if 'lanhu_Axure_Mapping_Data' in t: |
|||
i = t.find('lanhu_Axure_Mapping_Data') |
|||
hits.append((str(f.relative_to(P)), t[max(0, i-60):i+80])) |
|||
for rel, ctx in hits[:6]: |
|||
print(rel, '::', repr(ctx)[:200]) |
|||
print('total files hit:', len(hits)) |
|||
@ -0,0 +1,67 @@ |
|||
# A7 后台管理缺口总报告(票 02-05 矩阵汇总) |
|||
|
|||
四张矩阵:[matrix-a7-1-a7-2](matrix-a7-1-a7-2.md) / [matrix-a7-3-upper](matrix-a7-3-upper.md) / [matrix-a7-3-lower](matrix-a7-3-lower.md) / [matrix-a7-4-a7-5](matrix-a7-4-a7-5.md)。正式树 31 页全部过目完毕。 |
|||
|
|||
## 一、缺接口(按分区) |
|||
|
|||
| 分区 | 缺口 | 规模 | 备注 | |
|||
|---|---|---|---| |
|||
| A7-1 用户管理 | 批量分配角色、移交预览、移交执行、用户导出 | 4 端点(轻) | 分配/移交均为全量替换语义 | |
|||
| A7-1 同步任务页 | 同步任务 5 端点(列表/触发/详情/日志/重试) | 5 端点(**重**:对接钉钉任务调度) | 原型有独立页 | |
|||
| A7-2 角色管理 | roles stats / copy / enable / disable | 4 端点(轻) | | |
|||
| A7-2 权限点管理 | resources enable / disable / references | 3 端点(轻) | references 是删除前置校验页 | |
|||
| A7-3 方案推送规则 | 全缺码:page/detail/save-draft/publish/copy/disable/delete/versions | 8 端点(版本化族) | 4 步骤推送配置器(基础信息/字段校验/字段映射/创建关联项目),素材已提取 | |
|||
| A7-3 项目查重规则 | 全缺码:同版本化 8 端点 | 8 端点(版本化族) | 4 步骤查重向导(触发场景/关联项目检索/异常关系分析/处理策略),素材已提取 | |
|||
| A7-3 项目规则 | 全缺码:current + 5 分区保存(阶段别名/拉群人员/冲突拉群/阶段提醒/标底认定) | 6 端点(轻,聚合配置) | 阶段提醒区块原型自注「待补充」 | |
|||
| A7-3 线索规则 LeadPool | 部门成员字段 memberUserIds + 导入导出 2 端点 | 1 字段 + 2 端点(轻) | 成员语义待拍板(显式成员表 vs 部门动态) | |
|||
| A7-4 日志管理 | operation/login/batch 三 page + batch/download + batch/file + 全局日志表与采集 + 批量结果文件 90 天管理 | 5 端点 + 基建(**重**) | 实现形态方案 A/B 待拍板 | |
|||
|
|||
已确认无缺码:A7-1 用户列表核心/部门树、A7-2 角色管理核心/资源管理核心、A7-3 阶段模板族/方案卡模板族/公海与提醒族/客户规则 2 页/商机相关字典、A7-5 数据字典页。 |
|||
|
|||
## 二、缺入参 / 出参(轻改,随补码顺手做) |
|||
|
|||
- UserPageParam 缺 username/mobile/roleId/title;UserStatsDTO 出参缺 lastSyncTime/lastTransferTime/lastTransferUser |
|||
- RoleParam 缺 roleType/status;RoleDTO 出参缺 roleType/status/userCount |
|||
- 阶段模板 applyScope 缺条件式档(现有两档 vs 原型「招标形式=ZC」条件式) |
|||
- 公海规则 detail 出参缺绑定商机数量(P2:依赖商机侧落规则版本引用字段,建议记账后随商机模块对齐补) |
|||
- OpportunityPoolRule 列表如需「所属战队」等冗余列随 UI 确认 |
|||
|
|||
## 三、语义差异 / 拍板项 |
|||
|
|||
1. **资源删除语义相反**:现实现=子节点检查+级联清理引用;原型=有引用禁止删除。改行为影响现有调用方,需拍板。 |
|||
2. **LeadPool 部门成员**:显式成员表 vs 部门动态映射,语义拍板。 |
|||
3. **查重规则「执行次数」vs「引用次数」**:原型列头与字段说明矛盾,建议按「引用次数」(被推送规则引用锁定版本的次数)理解。 |
|||
4. **幻影挂账 3 项**:POST /depts/save、/depts/delete、/users/admin-role 原型无对应入口——保留(运维用)还是随文档重生成隐藏。 |
|||
5. **字典种子数据**:商机 4 分组(opportunity_stage 8 值/opp_status/pause_reason/close_reason)种子缺失。 |
|||
6. **dict 服务层 2 验证点**:默认项禁止停用阻断、未引用才可改分组(执行票顺带核)。 |
|||
|
|||
## 四、tag 待修清单(累计 12 处,随补码一次性改) |
|||
|
|||
| # | Controller | 现状 → 目标 | |
|||
|---|---|---| |
|||
| 1-4 | ResourceController 4 端点 | 「A7 后台管理/权限点管理」→ 补「权限管理」一级 | |
|||
| 5 | SystemController /sync/dingtalk | 「A7 后台管理/运维」→「A7 后台管理/用户管理/同步任务」 | |
|||
| 6 | LeadPoolController | A7 副本 tag →「A7 后台管理/业务规则/线索规则」 | |
|||
| 7 | OpportunityStageTemplateController | → 补「业务规则」一级:「…/业务规则/商机规则/商机阶段设置」 | |
|||
| 8 | OpportunitySchemeCardTemplateController | →「…/业务规则/商机规则/方案卡模板」 | |
|||
| 9 | OpportunityPoolRuleController | →「…/业务规则/商机规则/公海与提醒」 | |
|||
| 10-11 | CustomerReminderRule / CustomerDedupRule | →「…/业务规则/客户规则/客户管理设置(超期未跟进提醒 / 客户查重设置)」 | |
|||
| 12 | DictGroup/DictItem | → 补「系统设置」一级 + 方法级多值挂「…/业务规则/商机规则/商机相关字典」(ADR-0024) | |
|||
|
|||
## 五、待拍板四问 |
|||
|
|||
1. 本期补齐范围分档(P0 全做 / 重接口记账不做)。 |
|||
2. 新接口模块归属:推送规则+查重规则+项目规则是否进 crm-rule;全局日志放哪。 |
|||
3. 全局日志实现形态:A 新全局表+AOP 采集(域内三表保留服务详情页) vs B 聚合域内三表。 |
|||
4. A7-2-3 数据共享(backup 草稿箱 3 页)是否纳入盘点范围。 |
|||
|
|||
拍板后毕业执行票:补码 + 深 tag + bruno-sync 重生成 + 基线验收(编译过 / BOM 0 / 单测全绿 / 对账双向零差)。 |
|||
|
|||
--- |
|||
|
|||
## 六、执行收官标注(票 12,2026-09-07) |
|||
|
|||
执行票 07-12 全部 resolved,缺口处置终态如下(详细存证见各票 Answer): |
|||
|
|||
- **已执行**:缺接口 9 组中 7 组落地(用户管理 4 / 角色 4 / 权限点 3 / 推送规则 8 / 查重规则 8 / 项目规则 6 / LeadPool 1 字段+2 端点);缺入出参全落(UserPageParam×4 / UserStats 时间戳×3 / RoleParam×2 / RoleDTO×3 / 阶段模板条件式档);语义差异按票 06 拍板兑现(资源删除级联→禁删等);tag 12 处全修;bruno-sync 重生成对账双向零差(372=372)。 |
|||
- **已记账(本期不做)**:同步任务 5 端点(钉钉任务调度对接);全局日志 5 端点+新全局表+AOP+批量结果文件 90 天管理(归属新建 crm-log);公海规则 detail「绑定商机数量」出参(P2,依赖商机侧引用字段);A7-2-3 数据共享 3 页(等原型正式化)。 |
|||
@ -0,0 +1,45 @@ |
|||
# -*- coding: utf-8 -*- |
|||
"""生成 shots-index.md 对账表:截图 × 文本库 × 正式树归属""" |
|||
import json, io, sys |
|||
from pathlib import Path |
|||
|
|||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') |
|||
|
|||
ROOT = Path(r'e:\code\crm-backend-matt\.scratch\a7-parity') |
|||
TXT = Path(r'e:\code\crm-backend-matt\.scratch\opportunity-bugfix\lanhu-pages') |
|||
|
|||
shots = json.loads((ROOT / 'shot-a7.json').read_text(encoding='utf-8')) |
|||
txt_files = {f.stem.upper(): f.name for f in TXT.glob('A7-*.md')} |
|||
|
|||
# 正式树 31 页(sitemap A7 后台管理子树),backup 区 3 页 |
|||
BACKUP = {'a7-2-3_数据共享', 'a7-2-3-1_新建_编辑共享规则', 'a7-2-3-2_共享规则详情'} |
|||
|
|||
rows = [] |
|||
for s in sorted(shots, key=lambda x: x['page']): |
|||
name = s['page'] |
|||
key = name.upper() |
|||
txt = txt_files.get(key, '⚠缺失') |
|||
zone = 'backup' if name in BACKUP else '正式树' |
|||
rows.append(f"| {name} | {zone} | {txt} | {s['dim'][0]}x{s['dim'][1]} | {s['kb']}KB | {s['js_errors']} |") |
|||
|
|||
md = """# A7 截图落盘对账表(票 01 交付物) |
|||
|
|||
- 拉取: `.scratch/a7-parity/fetch-a7-pages.mjs`(OSS 直下 + 本地渲染目录)· 截图: `shot-a7.py`(Playwright fullPage) |
|||
- 蓝湖改写还原三件套: img data-src→src / link src→href / body display:none 剥离;渲染注入 `lanhu_Axure_Mapping_Data` 恒等 |
|||
- 文本库: `.scratch/opportunity-bugfix/lanhu-pages/A7-*.md`(34 文件) |
|||
- 清单: v29(`.scratch/lanhu-latest/axure-v29.json`)A7 共 34 页 = 正式树 31 + backup 草稿箱 3 |
|||
|
|||
| 页面 | 归属 | 文本库 | 尺寸(px) | 大小 | JS错误 | |
|||
|---|---|---|---|---|---| |
|||
""" |
|||
md += '\n'.join(rows) + '\n' |
|||
n_ok = len(shots) |
|||
md += f""" |
|||
## 结论 |
|||
|
|||
- 截图 {n_ok}/34 全部成功、js_errors 全 0;文本库对照零缺失。 |
|||
- 正式树 31 页(A7-1:2 / A7-2:5 / A7-3:20 / A7-4:3 / A7-5:1)+ backup「数据共享」3 页,验收口径达成(票面写 29 系建图时按 pages-index 口径误计,实为 31,map 已同步修正)。 |
|||
- 大页(宽 >6000px)共 14 张:批注区并排导致,文字缩放后偏小——盘点票以文本库为主、此类截图做结构/布局验证;需要细读时可对 pages/ 本地渲染做 viewport 分块截图。 |
|||
""" |
|||
(ROOT / 'shots-index.md').write_text(md, encoding='utf-8') |
|||
print(f'shots-index.md written, {n_ok} rows') |
|||
@ -0,0 +1,31 @@ |
|||
# -*- coding: utf-8 -*- |
|||
"""检查 team-page.html 资源引用形态 + team-mapping.json 结构""" |
|||
import re, json, io, sys |
|||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') |
|||
|
|||
html = open(r'e:\code\crm-backend-matt\.scratch\lanhu-latest\team-page.html', |
|||
encoding='utf-8', errors='replace').read() |
|||
print('=== script/link refs (first 15) ===') |
|||
for m in re.findall(r'<(?:script|link)[^>]*(?:src|href)="([^"]+)"', html)[:15]: |
|||
print(m) |
|||
print('=== img data-src (first 5) ===') |
|||
for m in re.findall(r'data-src="([^"]+)"', html)[:5]: |
|||
print(m) |
|||
print('=== total refs ===') |
|||
print('scripts/links:', len(re.findall(r'<(?:script|link)[^>]*(?:src|href)=', html)), |
|||
'imgs:', len(re.findall(r'data-src=', html))) |
|||
|
|||
m = json.load(open(r'e:\code\crm-backend-matt\.scratch\lanhu-latest\team-mapping.json', |
|||
encoding='utf-8')) |
|||
print('=== mapping top keys ===', list(m.keys())) |
|||
for k in m: |
|||
v = m[k] |
|||
n = len(v) if hasattr(v, '__len__') else '' |
|||
print(k, type(v).__name__, n) |
|||
if isinstance(v, list) and v: |
|||
print(' sample:', json.dumps(v[0], ensure_ascii=False)[:300]) |
|||
elif isinstance(v, dict): |
|||
ks = list(v.keys())[:5] |
|||
print(' keys:', ks) |
|||
if ks: |
|||
print(' sample:', json.dumps(v[ks[0]], ensure_ascii=False)[:300]) |
|||
@ -0,0 +1,32 @@ |
|||
# -*- coding: utf-8 -*- |
|||
"""提取 A7 页面清单(pages dict 的 key = 页面名.html)+ sitemap 归属""" |
|||
import json, io, sys |
|||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') |
|||
|
|||
doc = json.load(open(r'e:\code\crm-backend-matt\.scratch\lanhu-latest\axure-v29.json', encoding='utf-8')) |
|||
pages = doc['pages'] |
|||
|
|||
# ---- A7 页面(按 key 过滤,key = 页面名.html)---- |
|||
a7 = {k: v for k, v in pages.items() if k.upper().startswith('A7')} |
|||
print('=== A7 pages:', len(a7), '===') |
|||
for k, v in a7.items(): |
|||
print(f"{k} | mapping={v['mapping_md5']}") |
|||
|
|||
# ---- sitemap walk:输出每个叶子页的路径(区分正式树与草稿箱)---- |
|||
def walk(node, path, out): |
|||
name = node.get('pageName', '') |
|||
cur = path + [name] if node.get('type') != 'Axure:Page' else path |
|||
url = node.get('url') |
|||
if url: |
|||
out.append(('/'.join(cur), url)) |
|||
for ch in node.get('children') or []: |
|||
walk(ch, cur, out) |
|||
|
|||
leaves = [] |
|||
for rn in doc['sitemap']['rootNodes']: |
|||
walk(rn, [], leaves) |
|||
|
|||
a7_tree = [(p, u) for p, u in leaves if u.upper().startswith('A7')] |
|||
print('=== A7 in sitemap tree:', len(a7_tree), '===') |
|||
for p, u in a7_tree: |
|||
print(f'{u} <- {p}') |
|||
@ -0,0 +1,36 @@ |
|||
# 01 A7 全分区截图拉取落盘(视觉通路重建) |
|||
|
|||
Type: task |
|||
Status: resolved |
|||
Blocked by: |
|||
|
|||
## Question |
|||
|
|||
D 盘旧 Lanhu MCP 截图已随换机丢失,本票重建视觉通路并把 A7 全分区截图落到本仓: |
|||
|
|||
1. 用 OSS 直下管线(手册 `.scratch/lanhu-latest/RESEARCH-axure-pipeline.md`,可复用 fetch-*.mjs)拉取 A7 正式树 29 页的页面 HTML(v29 清单 `axure-v29.json` 已在本仓)。 |
|||
2. 用 `.scratch/customer-e2e/.venv10` 的 Playwright 无头浏览器逐页渲染,fullPage 截 PNG 到 `.scratch/a7-parity/shots/`(中文字体、长页完整性、Axure 动态渲染等待策略需验证;浏览器下载目录按 Playwright 环境搭建规范放 workspace 内)。 |
|||
3. 输出截图清单 + 与文本库 34 文件的对账表(缺失页、空页标注);backup 区「数据共享」3 页顺带截取备用。 |
|||
4. 交付物:shots 目录 + `shots-index.md` 对账表。 |
|||
|
|||
验收:29 页正式树每页有一张可读 PNG;对账表落盘。 |
|||
|
|||
## Answer(2026-09-07 resolved) |
|||
|
|||
**34/34 页全部成功(正式树 31 + backup 数据共享 3),js_errors 全 0,文本库对照零缺失。**交付:`shots/`(34 张 fullPage PNG)+ [shots-index.md](../shots-index.md) 对账表。 |
|||
|
|||
### 视觉通路终态(不依赖 MCP / Cookie / 外网登录态) |
|||
|
|||
1. `fetch-a7-pages.mjs`:OSS 直下按页拉取 HTML + mapping + 全部资源,按 mapping key 相对路径落盘到 `pages/<页名>/`(file:// 可直接渲染);全局 `oss-cache/` 按 sign_md5 去重(1827 下载 + 2435 命中,29.9MB)。 |
|||
2. `shot-a7.py`:`.venv10` Playwright 逐页 file:// 渲染 fullPage 截 PNG 到 `shots/`;`ctx.add_init_script` 注入恒等函数。 |
|||
3. **蓝湖对导出页面的三处改写必须还原**(本次排障逐一定位): |
|||
- `<img src>` → `data-src`(懒加载,不还原则图片全缺) |
|||
- `<link href>` → `src`(浏览器忽略 link 的 src,**三个 CSS 全部不加载,元素无尺寸全白屏**——最隐蔽的一处) |
|||
- `<body style="display:none;opacity:0">`(防闪烁隐藏,解除逻辑在蓝湖 web 端注入代码里,页面资源中没有 → 直接剥离) |
|||
- 另:data.js 被包成 `$axure.loadCurrentPage(lanhu_Axure_Mapping_Data({...}))`,该函数是蓝湖 CDN 端资源路径映射器、页面资源中无定义 → 注入恒等 `window.lanhu_Axure_Mapping_Data = d => d` 即可(本地渲染资源本就按相对路径落盘)。 |
|||
4. 大页(宽 >6000px)共 14 张:批注区并排所致,缩放后文字偏小——盘点票以文本库为主、截图验证结构布局;细读时对 `pages/` 本地渲染做 viewport 分块截图。 |
|||
|
|||
### 环境事实修正 |
|||
|
|||
- 正式树实为 **31 页**(票面 29 系建图时按 pages-index 口径误计),map 已同步修正。 |
|||
- Qoder 注册的 lanhu MCP(5 工具)`get_screenshot` 对 Axure 触发登录兕底(40441 user cancelled),Cookie 无注入通道——MCP 路线未用于本票;resolve_link 可用。用户提供的 Cookie 未落盘、未写入任何文件。 |
|||
@ -0,0 +1,25 @@ |
|||
# 02 A7-1 用户管理 + A7-2 权限管理 逐页对比 |
|||
|
|||
Type: task |
|||
Status: resolved |
|||
Blocked by: 01 |
|||
|
|||
## Question |
|||
|
|||
对 A7-1(用户列表 183 控件、同步任务 178)与 A7-2(角色管理 184、编辑角色基本信息/功能权限/数据范围 72+99+47、权限点管理 479)共 7 页做双源逐页对比(截图 + 文本库): |
|||
|
|||
1. **接口存在性**:页面按钮/入口 → 应有接口,对照 SystemController(用户 4 + 部门 3 + 钉钉同步)、RoleController(5)、ResourceController(4)、DataScopeModuleController(1)现有端点,标出缺失接口与幻影接口。 |
|||
2. **入参逐字段**:原型表单/筛选条件/操作列 vs 现有 Param/DTO 字段,标出缺失入参(重点:用户列表筛选条件、同步任务页、权限点管理表单、角色数据范围档位)。 |
|||
3. 出参仅记录明显缺失的返回块;顺带核对本分区存量端点的深 tag 是否已挂「A7 后台管理/…」完整页面路径(LeadPool 双归属不在本票范围,归 03 票)。 |
|||
4. 产出 `.scratch/a7-parity/matrix-a7-1-a7-2.md`(页面×接口矩阵 + 缺口清单,标注每条的「缺接口/缺入参/幻影/tag 待修」类型与原型证据行号)。 |
|||
|
|||
## Answer(2026-09-07) |
|||
|
|||
矩阵已交付:[matrix-a7-1-a7-2.md](../matrix-a7-1-a7-2.md)。要点: |
|||
|
|||
- **缺接口 9 组**:批量分配角色、移交预览+执行、用户导出;同步任务页 3 端点+设置 2 端点(重接口,需任务化+调度);角色 stats/copy/enable/disable;资源 enable/disable/references。 |
|||
- **缺入参**:UserPageParam 缺 username/mobile/roleId/title(筛选 6 项对齐);RoleParam 缺 roleType/status。 |
|||
- **缺出参块**:UserStatsDTO 缺三时间戳;RoleDTO 缺 status/userCount/roleType(「影响 N 人」各弹窗的数据源,跨页依赖)。 |
|||
- **语义相反 1 处**:资源删除现为「级联清理引用」,原型 A7-2-2 u218 要求「有引用禁止删除」——执行票需改写+引用校验。 |
|||
- **tag 待修 2 处**:/resources/* 补一级「权限管理」;/sync/* 改挂「用户管理/同步任务」。幻影挂账:depts/save、depts/delete、users/admin-role 原型无入口。 |
|||
- **意外发现**:ResourceServiceImpl 已按 v29 A7-2-2 对齐过一轮(perms 三类必填+全局唯一+编辑只读,注释直接引控件号 u200/u206)——权限点管理的新增/编辑链路基本合规,缺口集中在查询筛选/启停/删除语义。 |
|||
@ -0,0 +1,24 @@ |
|||
# 03 A7-3 业务规则·上半(线索规则/商机阶段/方案卡模板/方案推送规则)逐页对比 |
|||
|
|||
Type: task |
|||
Status: resolved |
|||
Blocked by: 01 |
|||
|
|||
## Question |
|||
|
|||
对 A7-3 上半共 10 页做双源逐页对比:线索规则(359 控件)、商机阶段设置(列表/详情/新增编辑 3 页)、方案卡模板(列表/详情/新增编辑 3 页)、方案推送规则(列表/详情/新增编辑 3 页,详情 502/编辑 460 控件): |
|||
|
|||
1. **线索规则**:核 LeadPoolController(/api/rule/pool/*)入参逐字段;核对双归属副本 tag「A7 后台管理/业务规则/线索规则」在文档仓是否齐全(票 04-reorg 交付物,验证其存量正确性)。 |
|||
2. **商机阶段设置/方案卡模板**:对照 crm-rule 的 OpportunityStageTemplateController、OpportunitySchemeCardTemplateController 现有端点,核存在性 + 入参逐字段(阶段流转条件、模板表单字段为高频缺口区)。 |
|||
3. **方案推送规则**:预期全缺码——列出原型应有的端点清单(列表/详情/新增/编辑/启停…)与每个端点的应有入参字段(来自原型表单),作为缺口报告的「新建模块」素材。 |
|||
4. 产出 `.scratch/a7-parity/matrix-a7-3-upper.md`(同 02 票矩阵格式)。 |
|||
|
|||
## Answer(2026-09-07) |
|||
|
|||
矩阵已交付:[matrix-a7-3-upper.md](../matrix-a7-3-upper.md)。要点: |
|||
|
|||
- **阶段模板/方案卡模板**:端点族已高度对齐(8/9 端点,版本状态机吻合 PRD);剩余为边缘缺口——适用范围缺条件式档(招标形式=ZC)、方案卡 page 缺两列字段数统计、字典项启用态校验。 |
|||
- **方案推送规则全缺码**:8 端点清单 + 4 步骤推送配置器 DTO 素材已从截图提取(基本信息/字段校验/字段映射/创建关联项目)。 |
|||
- **线索规则**:LeadPoolDTO 字段高度对齐,缺「部门成员」memberUserIds(语义待拍板)与导入/导出两端点。 |
|||
- **tag 待修 3 处**:三个 Controller 的 tag 均缺「业务规则」一级(对照 v29 权威树);阶段模板 tag 末级非页面名。 |
|||
- 文本库缺失的 4 页(阶段详情/编辑、推送详情/编辑)已用截图补源,提取成功。 |
|||
@ -0,0 +1,25 @@ |
|||
# 04 A7-3 业务规则·下半(项目查重/公海与提醒/商机字典/客户规则/项目规则)逐页对比 |
|||
|
|||
Type: task |
|||
Status: resolved |
|||
Blocked by: 01 |
|||
|
|||
## Question |
|||
|
|||
对 A7-3 下半共 10 页做双源逐页对比:项目查重规则(列表/详情/新增编辑 3 页,详情 591/编辑 561 控件)、公海与提醒规则(3 页)、商机相关字典(1 页 541 控件)、客户规则(超期未跟进提醒 35 + 客户查重设置 91)、项目规则(1 页 253 控件): |
|||
|
|||
1. **公海与提醒规则**:对照 OpportunityPoolRuleController 现有端点,核存在性 + 入参逐字段。 |
|||
2. **客户规则**:对照 CustomerReminderRuleController、CustomerDedupRuleController,核存在性 + 入参逐字段。 |
|||
3. **项目查重规则 / 商机相关字典 / 项目规则**:预期全缺码——列出原型应有的端点清单与入参字段(商机相关字典页 541 控件,注意与 crm-dict 既有字典能力的边界:是引用字典还是商机专用字典配置)。 |
|||
4. 产出 `.scratch/a7-parity/matrix-a7-3-lower.md`(同 02 票矩阵格式)。 |
|||
|
|||
## Answer |
|||
|
|||
resolved(2026-09-07)。产出 [matrix-a7-3-lower.md](../matrix-a7-3-lower.md),10 页双源逐页对比完毕(930/1241/1202 控件大页用文本库分段读完成,无需 OCR): |
|||
|
|||
1. **项目查重规则 3 页全缺码**:8 端点(/api/rule/opp-dedup-rule,版本化规则族同构 opp-pool-rule)+ 4 步骤向导 DTO 素材(触发场景/关联项目检索/异常关系分析[且或+括号嵌套]/处理策略)已提取;适用范围为条件式三档(全部商机/按项目属地/按所属公司)。 |
|||
2. **项目规则 1 页全缺码**:5 配置区块(阶段别名/拉群人员/冲突拉群/阶段提醒/标底认定 9 类型),预期 current+5 分区保存端点;模块归属为拍板项。 |
|||
3. **公海与提醒 3 页高度对齐**:三条件查询/操作矩阵/版本状态机/天数校验全部命中现有实现;唯一缺出参「绑定商机数量」(P2,依赖商机侧规则版本引用字段)。 |
|||
4. **商机相关字典无缺码**:crm-dict 13 端点+DTO 字段(itemCount/isDefault/referenced/effectiveSelectable)完全覆盖原型双页签;缺口仅为 4 分组种子数据与多值 tag 挂载。 |
|||
5. **客户规则 2 页逐字段对齐**:CustomerReminderRuleDTO 4 配置项、CustomerDedupRuleDTO 5 字段+信用代码强制无字段均与原型一致,零缺口。 |
|||
6. tag 待修 3 处(公海与提醒/超期未跟进提醒/客户查重设置,均缺「业务规则」一级,累计 10 处);原型矛盾拍板项 1 个(执行次数 vs 引用次数)。 |
|||
@ -0,0 +1,21 @@ |
|||
# 05 A7-4 日志管理 + A7-5 系统设置 逐页对比 |
|||
|
|||
Type: task |
|||
Status: resolved |
|||
Blocked by: 01 |
|||
|
|||
## Question |
|||
|
|||
对 A7-4(用户操作日志 175、登录日志 162、批量操作日志 188)与 A7-5(数据字典 380 控件)共 4 页做双源逐页对比: |
|||
|
|||
1. **日志三页**:预期全缺码(全局日志接口不存在,现有 Oplog/History 均为域内实体)——从原型提取每页的筛选条件字段、列表列、操作按钮,列出应有端点清单与入参字段;顺带记录现有域内日志实体(CustomerOplog/OpportunityOplog/LeadHistory)与原型列的映射关系,作为实现形态(全局表 vs 聚合)决策素材。 |
|||
2. **数据字典**:对照 DictGroupController/DictItemController 共 12 端点,核存在性 + 入参逐字段(分组/字典项表单、启用停用等)。 |
|||
3. 产出 `.scratch/a7-parity/matrix-a7-4-a7-5.md`(同 02 票矩阵格式)。 |
|||
|
|||
## Answer |
|||
|
|||
resolved(2026-09-07)。产出 [matrix-a7-4-a7-5.md](../matrix-a7-4-a7-5.md): |
|||
|
|||
1. **日志三页全缺码**:筛选/列表/交互全部提取完成;端点素材 5 个(/api/log 下 operation/login/batch 三 page + batch/download + batch/file);批量结果文件需落盘+90 天保留期管理(现状无)。实现形态决策素材已备齐:域内 OpportunityOplog/CustomerOplog/LeadHistory 三表均无 IP/账号/全局类型/结果/页面字段且以业务 ID 为轴,无法直接支撑全局审计页——方案 A(新全局表+AOP 采集,域内表保留服务详情页)vs 方案 B(三表补列 UNION 聚合)待票 06 拍板,倾向 A。 |
|||
2. **数据字典页无缺码**:双页签+二级字典项两级树+默认值/引用校验/停用联动全部命中 crm-dict 13 端点与 DTO 现有字段(itemCount/value/isDefault/referenced/effectiveSelectable/parentId);权限「仅平台超管」可由现有权限点种子等效;2 个服务层验证点(默认项禁停用、未引用才可改分组)留执行票顺带核。 |
|||
3. tag 待修 2 处(crm-dict 补「系统设置」一级 + 商机相关字典多值 tags,累计 12 处)。 |
|||
@ -0,0 +1,28 @@ |
|||
# 06 缺口汇总矩阵与补齐范围拍板 |
|||
|
|||
Type: grilling |
|||
Status: resolved |
|||
Blocked by: 02, 03, 04, 05 |
|||
|
|||
## Question |
|||
|
|||
汇总四张盘点票的矩阵成总缺口报告(三类:缺接口 / 缺入参 / tag 待修补),逐分区过目,用户拍板: |
|||
|
|||
1. 本期补齐范围(哪些缺接口建、哪些只记账;重接口如同步任务、批量日志是否本期——lead-docs-audit 先例「原型有按钮 ≠ 本期交付」)。 |
|||
2. 新接口模块归属(A7-4 全局日志放哪、crm-rule 是否收纳其余新规则 Controller)。 |
|||
3. 全局日志实现形态(全局表 + AOP vs 聚合域内 Oplog)。 |
|||
4. 「数据共享」backup 页纳入与否。 |
|||
5. 拍板后毕业执行票(补码 + 深 tag + bruno-sync 重生成 + 基线验收:编译过/BOM 0/单测全绿/对账双向零差),在本 effort 内收官。 |
|||
|
|||
## Answer |
|||
|
|||
(2026-09-07 拍板,四问均采纳推荐项) |
|||
|
|||
1. **补齐范围 = P0 全做,重接口记账**:[gap-report.md](../gap-report.md) §一 9 组缺接口中 P0 全建(A7-1/A7-2 轻 11 端点、推送规则 8、查重规则 8、项目规则 6、LeadPool 补齐+导入导出);重接口记账不建——同步任务 5 端点(钉钉调度对接)、全局日志 5 端点 + AOP 基建(原型有按钮 ≠ 本期交付),记账清单存档于 [12](12-bruno-regen-baseline.md)。 |
|||
2. **模块归属 = 规则进 crm-rule**:方案推送规则 / 项目查重规则 / 项目规则 Controller 全部归 crm-rule;全局日志若做归新建 crm-log 轻模块(不并入 crm-auth)。 |
|||
3. **日志形态 = A:新全局表 + AOP 采集**:域内三表(OpportunityOplog / CustomerOplog / LeadHistory)保留服务各域详情页轨迹,不动、不聚合。 |
|||
4. **数据共享 = 不纳入**:backup 3 页等原型正式化后再盘点(记账票 12)。 |
|||
|
|||
次级拍板默认值(随执行票落地):资源删除语义按原型改(级联清理→有引用禁删,发现现网依赖则停下报复议);LeadPool 部门成员 = 显式成员表(PoolMemberStore 增 DEPT_MEMBER);查重规则「执行次数」按引用次数理解;幻影挂账 3 端点保留、挂运维 tag。 |
|||
|
|||
执行票毕业:[07](07-a71-a72-light-endpoints.md) 与 [08](08-opp-push-rule-module.md) / [09](09-opp-dedup-rule-module.md) / [10](10-project-rule-leadpool.md) / [11](11-tags-dict-seed.md)(07–11 可并行)→ [12](12-bruno-regen-baseline.md)(收官,Blocked by 07–11)。 |
|||
@ -0,0 +1,31 @@ |
|||
# 07 A7-1+A7-2 轻接口补码(用户/角色/权限点) |
|||
|
|||
Type: task |
|||
Status: resolved(2026-09-07) |
|||
Blocked by: 06 |
|||
|
|||
## Question |
|||
|
|||
按 gap-report 拍板 P0,补齐 A7-1+A7-2 轻接口(素材 [matrix-a7-1-a7-2.md](../matrix-a7-1-a7-2.md)): |
|||
|
|||
1. SystemController 增 4 端点:POST /users/assign-roles-batch(多用户全量替换角色)、GET /users/transfer-preview?id=(移交预览:名下客户/商机/线索计数)、POST /users/transfer(移交执行:全量替换归属+快照)、GET /users/export(导出,走现有 file 模块)。UserPageParam 补 username/mobile/roleId/title;UserStatsDTO 出参补 lastSyncTime/lastTransferTime/lastTransferUser。 |
|||
2. RoleController 增 4 端点:GET /stats(roleCount/userCount 维度)、POST /copy、POST /enable、POST /disable。RoleParam 补 roleType/status;RoleDTO 出参补 roleType/status/userCount。 |
|||
3. ResourceController 增 3 端点:POST /enable、POST /disable、GET /references?id=(引用清单,供删除前置校验)。 |
|||
4. **资源删除语义按原型改**:现「子节点检查+级联清理引用」改为「有引用(角色绑定/菜单挂载)禁止删除,提示引用方」——执行时若发现现网调用方依赖级联语义,停下报票 06 复议。 |
|||
5. tag 修正 5 处:ResourceController 4 端点补「权限管理」一级;/sync/dingtalk 挂「A7 后台管理/用户管理/同步任务」。幻影挂账 3 项(depts/save、depts/delete、users/admin-role)保留端点、tag 挂「A7 后台管理/运维」。 |
|||
6. 出入参遵守 ADR-0017 Route A;新文件 UTF-8 无 BOM;孤立单大写字母字段 @Column 钉列名。 |
|||
|
|||
## Answer |
|||
|
|||
**resolved(2026-09-07)**。11 端点全落地,验收四项全过(BOM 771 文件 0 / mvn compile+test-compile 过 / 全仓 11 模块 1161 测试 0 失败 / 未提交 git)。执行记录与偏差: |
|||
|
|||
- **SystemController +4**(assign-roles-batch / transfer-preview / transfer / export): |
|||
- ⚠️ 偏差存证:票面「多用户全量替换角色」与原型 u296「**不会覆盖其已有角色**」矛盾,**按原型增量语义实现**(AuthUserServiceImpl.assignRolesBatch:逐用户查已有角色集仅插缺失行)。 |
|||
- 移交走 UserTransferPort seam(crm-base.service 定义,PermissionSeeder 同位;ObjectProvider 汇总,业务模块缺席不阻断启动):LeadUserTransferPortImpl(刷 owner 三列;dept_id 为池部门不跟人)/ CustomerUserTransferPortImpl(刷 owner 四列含 getDeptNames 部门名回显)/ Opportunity 与 Project 两域同表 crm_opportunity 按 opp_status 切分(AbstractOpportunityUserTransferPort 共享,!=5 / =5 STATUS_CONVERTED);批量 update 直改 owner 不走出站 E9 transition(CAS 仅允许状态 2/3,低频管理动作需覆盖全状态),域内轨迹不做、以 sys_user_transfer_log 全局快照追溯。 |
|||
- lastSyncTime:DtOrgSyncServiceImpl 成功尾部写 Redis(crm:auth:sync:last-sync-time,任务化时迁表挂账);UserStatsDTO 4→7 参补三时间戳;lastTransferTime/lastTransferUser 取移交日志最新一行。 |
|||
- export:EasyExcel 平铺 9 列(UserExportRow,时间格式化文本)→ FileApi.upload(bizDomain="system")。 |
|||
- **RoleController +4**:stats(复用 crm:role:list)/ copy / enable / disable(复用 crm:role:save),不改 DataInitializer。SysRole +roleType(SYS/MANAGE/BIZ/FUNC 服务层值域校验,null 允许兼容存量)/status(default enabled,对齐 SysMenu 先例);copyRole 产出停用草稿(原名-副本、roleCode=原码_copy_+6位随机段超50重造、复制 sys_role_menu 全套+RoleScopeStore 数据范围档位、不复制人员);enableRole 两道校验(≥1 menu 类型授权 + 四域 lead/opportunity/customer/project 档位齐全,已启用幂等);⚠️ 超票面:disableRole 加内置角色保护(builtin 拒停,对齐既有 delete 守卫);deleteRoleCascade 补在职使用人数守卫(仍在职用户命中则拒删)。 |
|||
- **ResourceController +3 + 语义改**:enable / disable / references;删除语义级联→禁删三段(①子节点 ②仅 disabled 可删,null 视为启用 ③被角色引用禁删并提示角色 ID 清单,不再级联清理 sys_role_menu);disable 被启用中角色引用也禁。现网调用方均为本模块 Controller,无外部依赖级联语义,未触发票 06 复议。 |
|||
- **tag 修正**:SystemController sync/dingtalk→用户管理/同步任务,depts/save、depts/delete→运维(幻影挂账三项之二,第三项 users/admin-role 端点本票未涉及);ResourceController 4 端点→A7 后台管理/权限管理/权限点管理。 |
|||
- **新错误码**:61019 移交参数非法 / 61020 资源被启用角色引用禁操作 / 61021 角色启用校验不过。 |
|||
- **测试**:受影响 6 文件同步修(计划 5 + PermissionSeederImplTest 的 H2 sys_role 补 role_type/status 两列;勘误:MP 3.5 的 saveOrUpdate(id=null) 走 BaseMapper.insertOrUpdate 而非 insert,copyRole verify 按此断言)+ 新增行为测试 15 个(角色 8:启停/复制草稿/统计/删除守卫;资源 7:启停/引用清单/禁删三段)。 |
|||
@ -0,0 +1,39 @@ |
|||
# 08 方案推送规则模块(crm-rule 全缺码补齐) |
|||
|
|||
Type: task |
|||
Status: resolved(2026-09-07) |
|||
Blocked by: 06 |
|||
|
|||
## Question |
|||
|
|||
按 gap-report 拍板 P0,新建方案推送规则模块(素材 [matrix-a7-3-upper.md](../matrix-a7-3-upper.md) §推送规则,端点族同构 OpportunityStageTemplate): |
|||
|
|||
1. `/api/rule/opp-push-rule` 下 8 端点:page / detail / save-draft / publish / copy / disable / delete / versions——版本化状态机复用既有实现模式(同族唯一草稿+唯一发布中、发布后原版转停用、复制=独立新编码 V1.0 草稿、仅草稿可删)。 |
|||
2. DTO 字段(截图提取):ruleCode PUSH_RULE_XX / ruleName / versionNo / status / applyScope(两档+条件式档可选)/ ruleDesc + 4 步骤配置 JSON: |
|||
- ①基础推送信息:推送节点名称、方案卡模板引用(锁定模板版本) |
|||
- ②字段校验:规则列表[{字段名称/字段来源/字段类型/校验规则/失败处理方式}] |
|||
- ③字段映射:[{字段名称/对应字段/推送方式}] |
|||
- ④创建/关联项目:创建方式(自动/交互/关联已有)、重复规则引用(**引用查重规则并锁定版本**,为票 09 的引用来源)、名称规则、备注变量 |
|||
3. Controller tag 直接写对:「A7 后台管理/业务规则/商机规则/方案推送规则」。 |
|||
4. bruno-sync.config.json 不需加 sourceRoots(crm-rule 已含);确认 menuBindings。 |
|||
|
|||
## Answer |
|||
|
|||
**resolved(2026-09-07)**。8 端点全落地,V-CONFIG 第四实例(extends {@link VersionedConfigSupport} 同款状态机)。 |
|||
|
|||
**落地清单(crm-rule,10 文件)**: |
|||
- 实体 `OpportunityPushRule`(表 opportunity_push_rule:rule_code/rule_name/version_no/status/apply_scope/condition_type/condition_value/is_default/rule_desc/push_config text)+ Mapper |
|||
- DTO(内嵌 `PushConfig` 4 步骤结构化对象:BasicInfo/FieldValidationItem/FieldMappingItem/ProjectCreation)/ VersionDTO(D-22 剥审计)/ PageParam |
|||
- `IOpportunityPushRuleService` + Impl(无运行时查询缝:执行侧未建) |
|||
- Controller `/api/rule/opp-push-rule` 8 端点(page/detail/save-draft/publish/copy/disable/delete/versions)+ 深 tag「A7 后台管理/业务规则/商机规则/方案推送规则」 |
|||
- `OpportunityPushRulePermissionInitializer`(@Order(21) 仅菜单,「商机管理/方案推送规则」) |
|||
- `OpportunityRuleConstants` 追加:前缀 PUSH_RULE_ / 适用范围 1,2 / 创建方式三值 / 错误码 64025–64030 |
|||
|
|||
**关键裁决与语义偏差存证**: |
|||
1. **适用范围两档 = 1全部商机 / 2条件式**(非阶段模板的部门档语义):条件式档必填 conditionType+conditionValue(原型示例「项目阶段='投标阶段'」存 condition_value;条件字段值域归前端配置器,服务层不强校验字典)。 |
|||
2. **推送配置 4 步骤单 push_config JSON 列(无子表)**:DTO 结构化出入参 ⇄ 服务层 ObjectMapper 序列化;序列化失败拒绝保存、反序列化失败防御为空不阻塞浏览;page 不回显(大 JSON 不进列表,明细走 detail);方案卡引用锁版本行 id(V-CONFIG 11 同款)、查重规则引用 dedupRuleId 为票 09 引用来源(票 09 落地后补存在性校验)。 |
|||
3. **发布校验**:步骤①必配 + 方案卡模板引用版本行存在 + 同名称发布中唯一(跨规则编码族——原型「同族同名单版本间不可重复」的落地解读,64029)+ 创建方式三值域(64030)。 |
|||
4. **默认顶替分组收敛**:同 applyScope(条件式含同 conditionType+conditionValue)内发布中默认唯一,异于阶段模板全局唯一(原型「同适用范围中设默认」)。 |
|||
5. **执行次数不出参**:按版本累计、执行侧归商机域未建(同构票 06「绑定商机」列已知裁决),执行侧落地后补统计源与运行时查询缝。 |
|||
6. bruno-sync:crm-rule 已在 sourceRoots(未动);menuBindings 无商机规则条目(同阶段模板/方案卡模板口径,未加)。 |
|||
7. 验收:BOM 117 文件 0 / compile EXIT=0 / crm-rule 175 测试全绿(新增 `OpportunityPushRuleServiceImplTest` 23 个规格验证)/ 未提交 git。 |
|||
@ -0,0 +1,40 @@ |
|||
# 09 项目查重规则模块(crm-rule 全缺码补齐) |
|||
|
|||
Type: task |
|||
Status: resolved(2026-09-07) |
|||
Blocked by: 06 |
|||
|
|||
## Question |
|||
|
|||
按 gap-report 拍板 P0,新建项目查重规则模块(素材 [matrix-a7-3-lower.md](../matrix-a7-3-lower.md) §一): |
|||
|
|||
1. `/api/rule/opp-dedup-rule` 下 8 端点:同版本化族(page/detail/save-draft/publish/copy/disable/delete/versions)。 |
|||
2. DTO 字段:ruleCode DUP_RULE_XX / ruleName / versionNo / status / **applyScopeType(1 全部商机 2 按项目属地 3 按所属公司)** / applyScopeValue(本地项目/南京公司…)/ isDefault / ruleDesc + 4 步骤向导 JSON: |
|||
- ①触发场景:triggerScenarios[](商机转项目/直接创建项目)、projectStatuses[](进行中/已中止暂停/已关闭/已结项) |
|||
- ②关联项目检索:searchConditions[{field/source/matchMode(完全一致|名称相似)/threshold}],默认 4 行=项目名称/项目区域/主要意向客户/甲方 |
|||
- ③异常关系分析:analysisRules[{seq/expression(且或+括号嵌套 JSON)/conclusion}],研判结论枚举 6 项 |
|||
- ④处理策略:strategies{intercept[]/confirm[]/normal[]}(适用研判结论多选) |
|||
3. 引用计数:被方案推送规则(票 08)引用锁定版本时维护 reference_count 按版本统计(原型「执行次数」列按「引用次数」理解——票 06 拍板项 3 默认值);草稿不可被引用。 |
|||
4. Controller tag 直接写对:「A7 后台管理/业务规则/商机规则/项目查重规则」。 |
|||
|
|||
## Answer |
|||
|
|||
**resolved(2026-09-07)**。8 端点全落地,V-CONFIG 第五实例(extends VersionedConfigSupport 同款状态机)。 |
|||
|
|||
**落地清单(crm-rule,9 新建 + 2 修改)**: |
|||
- 实体 `OpportunityDedupRule`(表 opportunity_dedup_rule:rule_code/rule_name/version_no/status/apply_scope_type/apply_scope_value/is_default/rule_desc/wizard_config text)+ Mapper |
|||
- DTO(内嵌 `WizardConfig` 4 步骤结构:triggerScenarios/projectStatuses/searchConditions[SearchCondition]/analysisRules[AnalysisRule]/strategies[Strategies])/ VersionDTO(含 referenceCount)/ PageParam |
|||
- `IOpportunityDedupRuleService` + Impl(无运行时查询缝:查重执行侧未建) |
|||
- Controller `/api/rule/opp-dedup-rule` 8 端点 + 深 tag「A7 后台管理/业务规则/商机规则/项目查重规则」 |
|||
- `OpportunityDedupRulePermissionInitializer`(@Order(22) 仅菜单,「商机管理/项目查重规则」) |
|||
- `OpportunityRuleConstants` 追加:前缀 DUP_RULE_ / 适用范围三档 / 触发场景与匹配方式值域 / 错误码 64031–64034 |
|||
- **修改**:`OpportunityPushRule` 实体加 dedup_rule_id 冗余列 + Impl 三分支提取落列 / 推送规则 validateForPublish 补查重引用校验 |
|||
|
|||
**关键裁决与语义偏差存证**: |
|||
1. **适用范围三档 = 1全部商机(可设默认)/ 2按项目属地(applyScopeValue 必填)/ 3按所属公司**;「是否默认[仅适用对象=全部时]」按原型钉死为服务层校验(非全部商机档设默认拒绝,64031),恢复阶段模板同款约束(票 08 推送规则因「同适用范围中设默认」语义未加此拦)。 |
|||
2. **4 步骤向导单 wizard_config JSON 列(无子表)**:同票 08 push_config 范式(DTO 结构化互转/序列化失败拒绝保存/损坏防御为空/page 不回显);条件表达式 expression 为嵌套 JSON 串透传(且/或+括号嵌套,结构由前端配置器定义,执行侧解析);触发场景/匹配方式值域常量钉死(OPP_TO_PROJECT/DIRECT_CREATE/EXACT/SIMILAR),研判结论 6 项与项目状态多选存 code 不强校验(配置器约束)。 |
|||
3. **引用计数 = 实时统计不落列**:票 06 拍板项 3「查重『执行次数』=引用次数」——出参 referenceCount = 引用本规则版本的推送规则行数(page 一次 in 查询分组计数 / detail·versions 逐版本 count;deleted 逻辑删自动排除;含草稿引用)。**实现中发现票 08 设计缺口:dedupRuleId 仅存 pushConfig JSON 无法 SQL 统计**,已补推送规则实体 dedup_rule_id 冗余列(保存三分支自步骤④提取落列、复制随行),JSON 与列双写。 |
|||
4. **「草稿不可被正式引用」(PRD)**:推送规则 validateForPublish 补校验——projectCreation.dedupRuleId 非空时须存在且发布中(64030),兑现票 08 Answer 承诺项。 |
|||
5. **无名称唯一发布校验**(原型无此约束,名称不参与查重匹配)——与推送规则(64029)刻意差异。 |
|||
6. **默认顶替分组收敛**:同 applyScopeType(属地档含同 applyScopeValue)内发布中默认唯一。 |
|||
7. 验收:BOM 127 文件 0 / 全仓 mvn test BUILD SUCCESS(crm-rule 190 测试:新增 DedupRuleServiceImplTest 15 + PushRule 补 dedupRuleId 校验回归 1)/ 未提交 git。 |
|||
@ -0,0 +1,29 @@ |
|||
# 10 项目规则模块 + LeadPool 补齐(crm-rule 杂项) |
|||
|
|||
Type: task |
|||
Status: resolved |
|||
Blocked by: 06 |
|||
|
|||
## Question |
|||
|
|||
按 gap-report 拍板 P0,补齐 crm-rule 剩余轻量缺口(素材 [matrix-a7-3-lower.md](../matrix-a7-3-lower.md) §五 / [matrix-a7-3-upper.md](../matrix-a7-3-upper.md) §线索规则): |
|||
|
|||
1. **项目规则模块**(全缺码,归属 crm-rule——票 06 拍板 2):`/api/rule/project-rule` 下 GET /current(聚合 5 区块回显)+ 5 分区全量表单保存:POST /stage-alias/save(7 阶段×显示别名)、POST /pool-member/save(7 角色×是否拉入开关)、POST /conflict-pull/save(5 行角色规则+2 触发条件复选)、POST /stage-remind/save(8 行提醒规则;原型自注「待补充」,按通用行结构落表)、POST /bid-config/save(9 标底类型×名称/说明/标底方%/中标方%/申请类型)。单例聚合配置模式(参照 CustomerReminderRule current+save)。 |
|||
2. **LeadPool 补「部门成员」**(票 06 拍板项 2 默认值:显式成员表):PoolMemberStore role_type 增 DEPT_MEMBER 枚举;LeadPoolDTO 增 memberUserIds(与 ownerUserId/collaboratorUserIds 并列的显式成员列);保存/回显走既有 PoolMemberStore 拆写模式。 |
|||
3. **LeadPool 导入导出 2 端点**:POST /import(Excel 模板批量)、GET /export(导出当前筛选结果)——走 crm-file 既有文件通路。 |
|||
4. **阶段模板 applyScope 条件式档**:OpportunityStageTemplateDTO.applyScope 增 3=条件式 + scopeCondition JSON(字段/操作符/值,如「招标形式=ZC」);随 DTO 顺手。 |
|||
5. Controller tag 直接写对:「A7 后台管理/业务规则/项目规则」「A7 后台管理/业务规则/线索规则」。 |
|||
6. 遵守 ADR-0017 / UTF-8 无 BOM / 孤立单大写字母 @Column 钉名 checklist。 |
|||
|
|||
## Answer |
|||
|
|||
已实施(2026-09-07),全部 6 子项落地,验收=mvn test -pl crm-rule -am BUILD SUCCESS(crm-rule 212 全绿)+BOM 0: |
|||
|
|||
1. **项目规则模块**:新建 ProjectRule 单例行(id=1,5 个 JSON text 列:stageAlias/poolMember/conflictPull/stageRemind/bidConfig)+ ProjectRuleDTO(5 区块结构化嵌套)+ IProjectRuleService/Impl(GET /current 聚合回显 + 5 分区保存,分区覆盖仅写对应列互不覆盖;行键非空/不重复/比例 0-100/触发复选 0/1 校验,失败 64036)。单例聚合模式对称 CustomerReminderRule(ProjectRuleInitializer @Order(23) 植入空骨架行;后端不编造字典键占位)。权限种子 ProjectRulePermissionInitializer @Order(24)(菜单「商机管理/项目规则」)。 |
|||
2. **LeadPool 部门成员**:RuleConstants 增 MEMBER_ROLE_DEPT_MEMBER=3;PoolMemberStore.replace 增第 4 参 memberUserIds(load 同步回填三类);去重优先级 负责人 > 协作人 > 部门成员(uk_pool_member 唯一约束池内一人一行)。 |
|||
3. **LeadPool 导入导出**:POST /import(EasyExcel 读 12 列模板,文件级守门 64035:空文件/扩展名/解析/无数据行;逐行走 self.savePool 部分成功,BatchResult<PoolImportFailItem> 行号+池名+文案)+ GET /export(导出筛选结果,ID 列+名称参考列同集闭环——无名称反查基建,模板以 ID 为准)。 |
|||
4. **阶段模板条件式档**:applyScope 增 3=条件式 + scopeCondition varchar(500);校验「条件式必填 scopeCondition」+沿用「仅所有商机可设默认」泛化为 scope != ALL 不可设默认;copy 同步复制。运行时查询缝(choose 按条件筛模板)不动——执行侧未建,按需扩展。 |
|||
5. **tag**:ProjectRuleController=「A7 后台管理/业务规则/项目规则」;LeadPoolController 5 端点=「A7 后台管理/业务规则/线索规则」。 |
|||
6. **纪律**:UTF-8 无 BOM(全模块扫描 0);无孤立单大写字母字段(memberUserIds/scopeCondition 均安全形态);写端点表单绑定/读端点 GET(ADR-0017)。 |
|||
|
|||
裁决存证:①区块行结构选 5 JSON text 列而非 5 张子行表——行是前端固定骨架渲染、后端全量覆盖(票 09 wizardConfig 同款范式);②导入模板以 ID 列为准——ISysDeptService/IAuthUserService 无名称反查且部门/用户名可重复;③导入部分成功自写逐行循环而非 BatchRunner——其输入定型 List<Long> 不适配行对象;④条件式不可设默认沿用阶段模板既有「仅 ALL 可设默认」约束而非推送规则的分组默认顶替——刻意差异。 |
|||
@ -0,0 +1,34 @@ |
|||
# 11 tag 全量修正 + 字典种子 + dict 验证点 |
|||
|
|||
Type: task |
|||
Status: resolved |
|||
Blocked by: 06 |
|||
|
|||
## Question |
|||
|
|||
轻改收尾(素材 [gap-report.md](../gap-report.md) §四 tag 表 + 票 07/10 已覆盖部分;本票只做 crm-rule/crm-dict 侧): |
|||
|
|||
1. tag 修正(累计 12 处中除票 07 覆盖的 5 处外): |
|||
- LeadPoolController A7 副本 →「A7 后台管理/业务规则/线索规则」 |
|||
- OpportunityStageTemplateController → 补「业务规则」一级:「A7 后台管理/业务规则/商机规则/商机阶段设置」 |
|||
- OpportunitySchemeCardTemplateController →「A7 后台管理/业务规则/商机规则/方案卡模板」 |
|||
- OpportunityPoolRuleController →「A7 后台管理/业务规则/商机规则/公海与提醒」 |
|||
- CustomerReminderRuleController →「A7 后台管理/业务规则/客户规则/客户管理设置(超期未跟进提醒)」 |
|||
- CustomerDedupRuleController →「A7 后台管理/业务规则/客户规则/客户管理设置(客户查重设置)」 |
|||
- DictGroupController →「A7 后台管理/系统设置/数据字典/分组」+ 方法级多值 tags 挂「A7 后台管理/业务规则/商机规则/商机相关字典」(ADR-0024 跨页共用) |
|||
- DictItemController →「A7 后台管理/系统设置/数据字典/字典项」+ 同上多值 |
|||
2. 字典种子数据(票 04 缺口④):商机 4 分组 + 字典值——opportunity_stage(OPP_STAGE_01 客户圈定/02 关系摸排/03 资料采集/04 方案卡/05~08 按原型 8 值)、opportunity_status、opportunity_pause_reason(OPP_PAUSE_01~04+99 其他)、opportunity_close_reason(OPP_CLOSE_01~05+99 其他)——种子机制沿用既有 permission-seeder seam 先例。 |
|||
3. dict 服务层 2 验证点(票 05 记录,非缺口顺带核):①默认项禁止停用阻断校验;②未被引用才可改分组。 |
|||
4. 全部 tag 改动后跑 bruno-sync 增量,确认无孤儿 .bru。 |
|||
|
|||
## Answer |
|||
|
|||
已实施(2026-09-07),验收 = mvn test -pl crm-dict,crm-rule -am BUILD SUCCESS(crm-dict 55 + crm-rule 212 全绿)+ BOM 0(java 源与 docs folder.bru 均扫)+ bruno-sync 增量无孤儿: |
|||
|
|||
1. **tag 修正 7 组**(票面第 1 组 LeadPoolController 已由票 10 兑现,实际 7 组):rule 侧 5 Controller 类级——阶段模板/方案卡模板/公海规则 →「A7 后台管理/业务规则/商机规则/{商机阶段设置|方案卡模板|公海与提醒}」、超期提醒/查重设置 →「A7 后台管理/业务规则/客户规则/客户管理设置(超期未跟进提醒|客户查重设置)」;dict 侧 DictGroup/DictItem 类级 →「A7 后台管理/系统设置/数据字典/{分组|字典项}」+ 全部 13 端点方法级多值 tags 挂「A7 后台管理/业务规则/商机规则/商机相关字典」(ADR-0024 跨页共用)。 |
|||
2. **字典种子**(DictDataInitializer 幂等 upsert):opp_stage 补 OPP_STAGE_06 技术交流/OPP_STAGE_07 竞品打压(01~04 补原型描述);新建 opportunity_status 分组 4 值(OPP_STATUS_01 推进中/02 暂缓中/03 已关闭/04 已转项目,对齐 OpportunityStatus 枚举业务四态)。 |
|||
3. **dict 2 验证点零代码**:默认项禁停(63013,saveItem+updateItemStatus 两处拦截)与「未被引用才可换组」(isReferenced+无子项+目标组启用+双重唯一+计数行随迁)实现与测试(DictItemServiceTest)均已存在,核对通过。 |
|||
4. **bruno-sync 增量**:bruno-sync.config.json menuBindings 旧 2 键 → 新 4 键(客户管理设置两页 + 数据字典分组/字典项);文档仓旧 7 目录 49 文件迁新 tag 路径(42 接口 .bru 逐字节搬移保表述 + 11 folder.bru 按 tag 重写)+「商机相关字典」13 份同名同内容副本 + 10 个旧空目录清理;git status 51 行无孤儿。 |
|||
5. **纪律**:UTF-8 无 BOM;DictDataInitializerTest 同步 7 处断言(25 组/235 项)。 |
|||
|
|||
裁决存证:①现有分组码一律不迁移——opp_stage 被 OpportunityRuleConstants.STAGE_DICT_GROUP_CODE 钉死、pause_reason 被状态机测试引用、bid_form 被 OpportunitySavedViewFilter 引用、pause/close 种子为产品录入 20260825 版,且原型 A7-3-2-6 自注「分组名称/编码/数量均为样例数据,不作验收数值」,票面 opportunity_stage/opportunity_pause_reason/opportunity_close_reason 样例码不采纳;②OPP_STAGE_05 保持「已转项目」(原型轨道图与编辑页自相矛盾,票 06 FIXED_STAGE_DICT_CODE 等四处强契约),「05=拟立项」样例不采纳;③OPP_STAGE_08 全原型库 0 匹配,不编造占位,opp_stage 实证 7 值;④opportunity_status 不含「待领取」——公海池归属态非业务状态,只取枚举 2-5。 |
|||
@ -0,0 +1,50 @@ |
|||
# 12 bruno-sync 重生成 + 基线验收收官 |
|||
|
|||
Type: task |
|||
Status: resolved |
|||
Blocked by: 07, 08, 09, 10, 11 |
|||
|
|||
## Question |
|||
|
|||
本 effort 收官票——全部补码与 tag 修正落地后: |
|||
|
|||
1. 跑 bruno-sync 全量重生成文档仓(`E:\code\crm-api-docs`,bare collection 布局):新接口按深 tag 机制新建页面文件夹(A7-1 用户管理/同步任务/权限管理/业务规则三族/项目规则等);存量二级目录不动(api-docs-reorg 既定裁决)。 |
|||
2. 对账双向零差:代码端点 ↔ .bru 文件,扫差脚本跑两向。 |
|||
3. 基线验收(执行基线沿用先例):`mvn compile` 过 + 全仓 *.java BOM 扫描 0 + 单测全绿。 |
|||
4. 文档仓改动不提交 git,留用户审查(铁律)。 |
|||
5. 本 effort 收官:map.md 状态置 done,缺口语义在 gap-report 追加「已执行/已记账」标注。 |
|||
|
|||
## 记账清单(本期不做,拍板存档) |
|||
|
|||
- 同步任务 5 端点(重:钉钉任务调度对接) |
|||
- 全局日志 5 端点 + 全局日志表 + AOP 采集 + 批量结果文件 90 天管理(重:**形态已拍板=A 新全局表+AOP,域内三表保留服务详情页**;归属新建 crm-log 轻模块) |
|||
- 公海规则 detail 出参「绑定商机数量」(P2:依赖商机侧落规则版本引用字段) |
|||
- A7-2-3 数据共享 backup 3 页(等原型正式化后再盘点) |
|||
- LeadPool 导入导出若 crm-file 通路不足则随票 10 报障 |
|||
|
|||
## Answer |
|||
|
|||
2026-09-07 收官执行完毕,验收全过: |
|||
|
|||
### 1. bruno-sync 全量重生成(文档仓 E:\code\crm-api-docs,全工作区改动未提交 git) |
|||
|
|||
- **批 A 搬移 12 文件**(tag 改名旧位置孤儿清零):权限点管理 4 → 权限管理\权限点管理;线索规则 5 → 业务规则\线索规则;运维\钉钉组织同步 → 用户管理\同步任务;部门管理{保存,删除}部门 → 运维。复制前+删旧前双重验证,moved=12、空目录 rmdir=2。 |
|||
- **批 B 新建 37 文件**(37 纯新建钥匙逐个生成;先落暂存树 `.scratch/a7-parity/t12-bru\` 再整树复制部署 copied=37 errors=0): |
|||
- B1 权限管理:权限点 3(启用/停用/引用清单)+ 角色 4(统计/复制/启用/停用) |
|||
- B2 用户管理 4(批量分配角色/移交预览/移交执行/导出用户列表)+ LeadPool 导入导出 4 文件(A7 业务规则\线索规则 + A2 线索设置 双 tag 同内容副本) |
|||
- B3 商机规则:方案推送规则 8 + 项目查重规则 8(分页/详情/草稿/发布/复制/停用/删除/版本列表;pushConfig/wizardConfig 嵌套结构全字段表;分页不回显大 JSON、detail 回显、versions 剥审计字段带引用计数) |
|||
- B4 项目规则 6(读当前配置聚合 5 区块 + 5 分区保存;嵌套 List 属性路径表单绑定;骨架键取 ProjectRuleConstants 真值:7 角色键/5 冲突行键/9 标底键) |
|||
- **对账**(bruno_scan_d.py 复用):source_key_count 372 = generated_file_count 372,keep 372 / new 0 / delete 0 / unrecognized 0 / conflicts 0 / private 0 —— **双向零差**。 |
|||
|
|||
### 2. 基线验收 |
|||
|
|||
- 全仓 *.java BOM 扫描 0。 |
|||
- mvn compile 过(环境通道:PATH 无 mvn/java,JAVA_HOME=IDEA JBR + Maven 用 IDEA bundled maven3)。 |
|||
- 全仓单测:9 模块 **1221 全绿**(base 44 / file 84 / auth 224 / dict 55 / rule 212 / preference 23 / customer 131 / lead 186 / opportunity 262;= 票 07 收官时 1161 + 票 08/09/10 新增 60,数字闭环)。 |
|||
- **修复一处票 10 遗留漏网**:OpportunityBoardIntegrationTest 内嵌 H2 DDL 缺 `scope_condition` 列(票 10 条件式档加列未同步 opportunity 侧集成测试 DDL;票 10/11 验收只跑 crm-rule/dict 侧,本票全仓首跑暴露)→ DDL 补 `scope_condition VARCHAR(500)` 可空(对齐实体 @Column),重跑全绿。 |
|||
|
|||
### 3. 收官状态 |
|||
|
|||
- 文档仓改动全数留在工作区未提交;后端仓仅上述 1 处测试 DDL 同步修,同样未提交,留用户审查。 |
|||
- 记账清单 4 项保持不做(见票面),gap-report 已追加「执行收官标注」。 |
|||
- map.md 已记账票 12 行;执行票 07-12 全 resolved,**本 effort 收官**。 |
|||
@ -0,0 +1,8 @@ |
|||
import os |
|||
|
|||
d = r'.scratch\opportunity-bugfix\lanhu-pages' |
|||
names = sorted(f for f in os.listdir(d) if f.startswith('A7-3')) |
|||
out = r'.scratch\a7-parity\a73-files.txt' |
|||
with open(out, 'w', encoding='utf-8') as fh: |
|||
fh.write('\n'.join(names)) |
|||
print('OK', len(names)) |
|||
@ -0,0 +1,52 @@ |
|||
# Map: A7 后台管理原型-代码逐页对齐(缺口盘点与文档划分) |
|||
|
|||
Label: wayfinder:map · charted 2026-09-07 |
|||
|
|||
## Destination |
|||
|
|||
A7 后台管理全分区(正式树 31 页:A7-1 用户管理 / A7-2 权限管理 / A7-3 业务规则 / A7-4 日志管理 / A7-5 系统设置;另有 backup 草稿箱「数据共享」3 页)完成「蓝湖原型 × 现有代码」双源逐页对比,产出页面×接口矩阵与缺口报告(缺失接口 / 缺失入参);用户拍板补齐范围后补码 + 源码深 tag + bruno-sync 重生成文档仓,本 effort 内收官。 |
|||
|
|||
## Notes |
|||
|
|||
- 五项 charting 拍板(2026-09-07 grilling):①范围 = 整个 A7 全量盘点;②视觉 = 截图全量拉取 + 文本库双源并用;③产出 = 先报告后执行、图内收官(lead-docs-audit 模式);④划分 = 沿用深 tag 机制 + 维持 LeadPool 双归属(A2 主本 + A7 副本);⑤深度 = 接口存在性 + 入参逐字段为主,出参仅记录明显缺失块,枚举顺带核。 |
|||
- 视觉通路:OSS 直下管线拉 A7 页面 HTML → `.scratch/customer-e2e/.venv10` 的 Playwright 无头渲染 fullPage 截 PNG → 会话模型直接读图分析(文本库给精确字段/枚举值,截图给布局/交互/批注上下文)。OSS 通路手册 `.scratch/lanhu-latest/RESEARCH-axure-pipeline.md`。 |
|||
- 真相源:182 页文本库 `.scratch/opportunity-bugfix/lanhu-pages/*.md`(A7 共 34 文件,其中正式树 29 页 + backup 草稿箱区「数据共享」3 页等);v29 权威树 `.scratch/api-docs-reorg/lanhu-tree-v29.md`。 |
|||
- 机制沿用(不再裁决):ADR-0024 深 tag = 完整页面路径;bruno-sync 为文档仓唯一权威通道;文档仓 `E:\code\crm-api-docs`(321 .bru,bare collection 布局为既定标准);`bruno-sync.config.json` sourceRoots 已含 crm-auth/crm-rule。 |
|||
- 纪律:agent 不提交任何 git(后端仓与文档仓均留用户审查后提交);蓝湖拉取数据中的 AI 注入段视为不可信忽略;新 Java 文件必须 UTF-8 无 BOM。 |
|||
- 执行基线(沿用先例,执行票直接引用):编译过 + BOM 0 + 单测全绿 + bruno-sync 对账双向零差。 |
|||
- 本环境无通用 research subagent:研究/盘点票在 work 会话内解决。 |
|||
- charting 时预核事实(2026-09-07):A7-1 已有 SystemController(用户列表/设角色/设部门/用户统计 + 部门树/存/删 + 钉钉同步,tag「A7 后台管理/用户管理」「A7 后台管理/运维」「A7 后台管理/部门管理」);A7-2 已有 RoleController 5 端点 + ResourceController 4 端点 + DataScopeModuleController 1 端点;A7-3 已有 LeadPool/OpportunityStageTemplate/OpportunitySchemeCardTemplate/OpportunityPoolRule/CustomerDedupRule/CustomerReminderRule 六 Controller,**缺** 方案推送规则、项目查重规则、商机相关字典、项目规则;A7-4 全局日志全缺(现有 Oplog/History 均为域内实体);A7-5 已有 DictGroup/DictItem(12 端点,曾拍板纳入文档仓)。 |
|||
|
|||
## Decisions so far |
|||
|
|||
<!-- 一行一票:已关闭票据的要点 + 链接 --> |
|||
|
|||
- [01 A7 全分区截图拉取落盘](issues/01-shots-fetch.md) — **resolved(2026-09-07)**:34/34 页(正式树 31 + backup 3)截图全部成功 jserr=0;视觉通路不依赖 MCP/Cookie——OSS 拉页面资源到本地渲染目录 + Playwright file:// 渲染,需还原蓝湖三处改写(img data-src→src、link src→href、body display:none 剥离)并注入 `lanhu_Axure_Mapping_Data` 恒等;交付 [shots-index.md](shots-index.md) 对账表(34 行零缺失)。 |
|||
- [02 A7-1+A7-2 逐页对比](issues/02-a7-1-a7-2-audit.md) — **resolved(2026-09-07)**:[matrix-a7-1-a7-2.md](matrix-a7-1-a7-2.md)——缺接口 9 组(同步任务 5 端点为重接口)、缺入参 UserPageParam×4/RoleParam×2、缺出参 UserStats 时间戳/RoleDTO status+userCount+roleType;资源删除语义与原型相反(级联清理 vs 禁止删除);tag 待修 /resources/* 与 /sync/*;幻影挂账 3 项。 |
|||
- [03 A7-3 上半逐页对比](issues/03-a7-3-upper-audit.md) — **resolved(2026-09-07)**:[matrix-a7-3-upper.md](matrix-a7-3-upper.md)——阶段/方案卡模板端点族已高度对齐;方案推送规则全缺码(8 端点+4 步骤配置器,截图补源提取);LeadPool 缺部门成员字段+导入导出;tag 待修 3 处(均缺「业务规则」一级)。 |
|||
- [04 A7-3 下半逐页对比](issues/04-a7-3-lower-audit.md) — **resolved(2026-09-07)**:[matrix-a7-3-lower.md](matrix-a7-3-lower.md)——项目查重/项目规则全缺码(8 端点版本化族+5 区块配置);公海与提醒高度对齐仅缺绑定商机数出参;商机相关字典无缺码(crm-dict 覆盖,缺种子数据);客户规则 2 页逐字段对齐零缺口;tag 待修 3 处(累计 10 处)。 |
|||
- [05 A7-4 日志 + A7-5 字典逐页对比](issues/05-a7-4-a7-5-audit.md) — **resolved(2026-09-07)**:[matrix-a7-4-a7-5.md](matrix-a7-4-a7-5.md)——日志三页全缺码(5 端点素材+批量结果文件 90 天管理;域内三表无全局审计字段,方案 A 新表+AOP vs B 聚合待拍板);数据字典页无缺码(13 端点全覆盖含二级字典项);tag 待修 2 处(累计 12 处)。 |
|||
- [06 缺口汇总拍板 + 执行票毕业](issues/06-gap-verdict.md) — **resolved(2026-09-07)**:[gap-report.md](gap-report.md)——缺接口 9 组 / 缺入出参若干 / 语义差异 6 项 / tag 12 处。四问拍板:①P0 全做,重接口(同步任务 5 端点、全局日志 5 端点+AOP)记账不建;②新规则 Controller 归 crm-rule,全局日志若做归新建 crm-log;③日志形态 A(新全局表+AOP 采集,域内三表保留服务详情页轨迹);④数据共享 3 页不纳入。次级默认值:资源删除语义按原型改(级联→禁删)、LeadPool 部门成员=显式成员表 DEPT_MEMBER、查重「执行次数」=引用次数、幻影挂账 3 端点保留挂运维 tag。执行票毕业:[07](issues/07-a71-a72-light-endpoints.md)(轻 11 端点+资源删除语义+tag 5 处)/ [08](issues/08-opp-push-rule-module.md)(推送规则 8 端点)/ [09](issues/09-opp-dedup-rule-module.md)(查重规则 8 端点+4 步骤向导)/ [10](issues/10-project-rule-leadpool.md)(项目规则 6 端点+LeadPool+导入导出+条件式档)/ [11](issues/11-tags-dict-seed.md)(tag 8 处+字典 4 分组种子+dict 2 验证点)→ [12](issues/12-bruno-regen-baseline.md)(bruno 重生成+对账+基线验收+记账清单,Blocked by 07–11)。**Map 决策阶段收官(01–06 全 resolved);执行票 07–12 开放。** |
|||
- [07 A7-1+A7-2 轻接口补码](issues/07-a71-a72-light-endpoints.md) — **resolved(2026-09-07)**:11 端点全落地;⚠️ 批量分配角色按原型 u296 改**增量语义**(票面「全量替换」系笔误,Answer 存证);移交走 UserTransferPort seam(crm-base 定义 + 4 模块实现,opportunity/project 同表按 opp_status 切分)+ sys_user_transfer_log 全局快照;lastSyncTime Redis 暂存(key crm:auth:sync:last-sync-time,任务化迁表挂账);角色 status/roleType + stats/copy/enable/disable(enable 两道校验、copy 停用草稿不复制人员、disable 加内置角色保护系超票面防御);deleteRoleCascade 补在职使用人数守卫;资源删除级联→禁删三段 + enable/disable/references;tag 修正 5 处+幻影挂运维;新错误码 61019–61021;受影响 6 测试文件同步修(含 PermissionSeederImplTest 补 H2 列、MP 3.5 insertOrUpdate 勘误)+新增 15 行为测试;全仓 1161 测试 0 失败、BOM 0。 |
|||
- [08 方案推送规则模块](issues/08-opp-push-rule-module.md) — **resolved(2026-09-07)**:8 端点全落地(V-CONFIG 第四实例 extends VersionedConfigSupport);适用范围条件式两档(1全部商机/2条件式+conditionType+conditionValue,异于阶段模板部门档);推送配置 4 步骤单 push_config JSON 列(无子表,DTO 结构化互转,损坏防御为空,page 不回显);发布校验=步骤①必配+方案卡引用版本行存在+同名称发布中唯一(跨编码族 64029)+createMode 三值域;默认顶替按同适用范围(条件式含同条件值)分组收敛(异于阶段模板全局唯一);执行次数不出参(执行侧归商机域未建,同构「绑定商机」裁决);错误码 64025–64030;权限种子 @Order(21) 仅菜单;测试+23(推送规则状态机规格),crm-rule 175 测试全绿、BOM 0。 |
|||
- [09 项目查重规则模块](issues/09-opp-dedup-rule-module.md) — **resolved(2026-09-07)**:8 端点全落地(V-CONFIG 第五实例);适用范围三档(1全部商机可设默认/2按项目属地+applyScopeValue 必填/3按所属公司),非全部商机档设默认拒绝(恢复阶段模板同款约束);4 步骤向导单 wizard_config JSON 列(expression 嵌套 JSON 串透传,触发场景/匹配方式值域钉死,研判结论/项目状态不强校验);引用计数=实时统计不落列(票 06 拍板「执行次数=引用次数」:推送规则实体补 dedup_rule_id 冗余列自步骤④提取落列,page in 查询分组计数/detail·versions 逐版本 count);「草稿不可被正式引用」推送规则发布校验兑现(dedupRuleId 存在+发布中,64030);无名称唯一校验(与推送规则刻意差异);默认顶替同 applyScopeType(属地含同 value)分组;错误码 64031–64034;权限种子 @Order(22) 仅菜单;测试+16(查重规格 15+推送规则回归 1),全仓测试全绿、BOM 0。 |
|||
- [10 项目规则 + LeadPool 补齐](issues/10-project-rule-leadpool.md) — **resolved(2026-09-07)**:项目规则 6 端点全落地(GET /current 聚合回显 + 5 分区保存;单例行 id=1 五 JSON text 列分区覆盖、区块互不覆盖、损坏防御为空;Initializer @Order(23) 空骨架行,后端不编造字典键占位);LeadPool 部门成员=显式成员表 role_type=3(replace 四参+load 三类回填,去重优先级 负责人>协作人>部门成员);导入导出 2 端点(文件级守门 64035,逐行 self.savePool 部分成功 BatchResult,模板 ID 列为准+名称参考列同集闭环);阶段模板 applyScope 条件式档(3=条件式+scopeCondition 必填、「仅 ALL 可设默认」泛化为非 ALL 拒默认、copy 同步;运行时查询缝不动);tag:LeadPool 5 端点补「业务规则」一级、项目规则两级新建;错误码 64035–64036;权限种子 @Order(24) 仅菜单;测试+21(LeadPool 透传+导入导出 6 / Store 去重 3 / 条件式 3 / 项目规则规格 9),crm-rule 212 全绿、BOM 0。 |
|||
- [11 tag 全量修正 + 字典种子 + dict 验证点](issues/11-tags-dict-seed.md) — **resolved(2026-09-07)**:tag 7 组全修(LeadPool 已由票 10 兑现;rule 5 Controller 类级补「业务规则」一二级;DictGroup/DictItem 类级迁「系统设置/数据字典」+13 端点方法级多值挂「商机相关字典」ADR-0024 跨页共用);字典种子:opp_stage 补 06 技术交流/07 竞品打压(01~04 补描述;05 已转项目守票 06 强契约;08 原型无值不编造)+新建 opportunity_status 4 值(推进中/暂缓中/已关闭/已转项目;待领取系公海归属态不入组);现有分组码不迁移(被常量/状态机/视图筛选/产品录入 20260825 钉死,原型样例码不采纳——原型自注样例不作验收数值);dict 2 验证点(默认项禁停 63013/未引用才可换组)实现+测试已存在零代码;bruno-sync 增量:menuBindings 2→4 键、文档仓旧 7 目录 49 文件迁新 tag 路径(42 接口逐字节搬+11 folder.bru 重写)+商机相关字典 13 同内容副本+10 空目录清理、git 51 行无孤儿;crm-dict 55(种子断言 25 组/235 项)+crm-rule 212 全绿、BOM 0。 |
|||
- [12 bruno-sync 重生成 + 基线验收收官](issues/12-bruno-regen-baseline.md) — **resolved(2026-09-07)**:文档仓批 A 搬移 12(tag 改名旧位置清零)+批 B 新建 37(权限点 3/角色 4/用户 4/LeadPool 导入导出 4/推送 8/查重 8/项目规则 6;暂存树→整树复制部署);对账双向零差(bruno_scan_d.py:source 372=generated 372,keep 372/new 0/delete 0/unrecognized 0);基线验收 BOM 0+mvn compile 过+全仓 9 模块 1221 测试全绿(修复票 10 遗留漏网:OpportunityBoardIntegrationTest 内嵌 H2 DDL 补 scope_condition 列);记账清单 4 项存档不做、gap-report 收官标注。执行票 07-12 全 resolved,**本 effort 收官**;文档仓与后端仓改动均未提交 git,留用户审查。 |
|||
|
|||
## Not yet specified |
|||
|
|||
(原五项悬置已随票 06 拍板全部闭合,存档如下:) |
|||
|
|||
- ~~新接口的模块归属~~ → 已拍板(票 06 问 2):规则 Controller 归 crm-rule;全局日志若做归新建 crm-log。 |
|||
- ~~重接口本期边界~~ → 已拍板(票 06 问 1):P0 全做;同步任务 5 端点 / 全局日志 5 端点记账不做(票 12 记账清单存档)。 |
|||
- ~~A7-2-3 数据共享纳入与否~~ → 已拍板(票 06 问 4):不纳入,等原型正式化。 |
|||
- ~~全局日志实现形态~~ → 已拍板(票 06 问 3):形态 A 新全局表 + AOP 采集。 |
|||
- ~~执行票拆分~~ → 已毕业:[07](issues/07-a71-a72-light-endpoints.md)–[12](issues/12-bruno-regen-baseline.md) 六张执行票开放(07–11 可并行,12 收官)。 |
|||
|
|||
## Out of scope |
|||
|
|||
- 非 A7 分区(A0-A6)的接口盘点与文档改动。 |
|||
- 存量文档仓二级目录的批量重排(api-docs-reorg 既定裁决「二级及更深一律不动」;本次仅为新增接口按深 tag 机制新建页面文件夹)。 |
|||
- swagger UI 美化、sys_menu 种子菜单数据迁移(ADR-0024 既有遗留)。 |
|||
- 原型中非 A7 空缺模块(A1X 工作计划、A6 数据看板等)的接口实现。 |
|||
@ -0,0 +1,130 @@ |
|||
# 矩阵:A7-1 用户管理 + A7-2 权限管理(票 02) |
|||
|
|||
- 口径:拍板⑤——接口存在性 + 入参逐字段为主,出参仅记明显缺失块;深 tag 顺带核(拍板④)。 |
|||
- 双源:文本库 `.scratch/opportunity-bugfix/lanhu-pages/A7-1*.md / A7-2*.md`(证据=控件 id)+ 截图 `shots/a7-1*.png / a7-2*.png`(结构验证)。 |
|||
- 类型标注:**缺接口** / **缺入参** / **缺出参块** / **校验差距** / **幻影**(代码有原型无)/ **tag 待修** / ✅已覆盖。 |
|||
- 正式树 7 页全盘;backup「数据共享」3 页不在本票(留票 06 拍板)。 |
|||
|
|||
## 一、A7-1-1 用户列表(文本库 194 行) |
|||
|
|||
| # | 原型要素 | 证据 | 应有接口 | 现状 | 差距 | |
|||
|---|---|---|---|---|---| |
|||
| 1 | 左栏钉钉部门树(点击过滤右侧列表) | u67/u360 | 部门树 | GET /api/system/depts/tree | ✅ | |
|||
| 2 | 统计卡片:部门总数/在职员工/离职员工/待分配员工 | u209-u212/u360 | 用户统计 | GET /users/stats(UserStatsDTO 四指标对齐) | **缺出参块**:三个时间戳(最近同步×2、最近移交,u209-u211)DTO 无字段 | |
|||
| 3 | 筛选:姓名/手机号码/部门/所属角色/状态/职务 | u107/u84/u109/u110/u146/u155 | 列表查询 | POST /users/page(UserPageParam: deptId/employmentStatus/loginFrom/loginTo) | **缺入参**:username、mobile、roleId、title;loginFrom/loginTo 原型无此筛选(代码多余项,可留) | |
|||
| 4 | 职务下拉枚举值域(营销副总裁/维度管理总监/…) | u156 | — | 无 | **缺口(挂账)**:值域来源待定(OA title 去重 or 字典) | |
|||
| 5 | 表格列:姓名/手机号/部门/所属角色/状态/最后登录时间 | u183-u188 | — | UserListDTO 全字段齐 | ✅ | |
|||
| 6 | 行内「分配角色」弹窗(在职/待分配) | u197-u200/u362 | 保存该用户角色 | POST /users/assign-roles(单用户全量替换) | ✅ | |
|||
| 7 | 弹窗角色清单带「影响 N 人」「启用中」 | u266-u289 | 角色列表 | — | 依赖 A7-2-1 的角色 status/userCount 缺口(见三) | |
|||
| 8 | 「批量配置角色」弹窗:多选员工+增量授予(「不会覆盖其已有角色」) | u201/u254-u314/u296 | 批量分配 | — | **缺接口**:POST /users/batch-assign-roles(userIds+roleIds,增量语义) | |
|||
| 9 | 行内「移交数据」弹窗(已离职):接收人+待移交数量(线索/客户/商机/项目) | u317-u338/u368 | 移交预览+执行 | — | **缺接口**×2:移交预览(分域数量)、移交执行(userId+receiverId,跨域改 owner) | |
|||
| 10 | 「导出数据」按钮(筛选区右侧) | u108/u360 | 导出 | — | **缺接口**:用户列表导出(同筛选入参,返文件流) | |
|||
|
|||
## 二、A7-1-2 同步任务(文本库 189 行) |
|||
|
|||
| # | 原型要素 | 证据 | 应有接口 | 现状 | 差距 | |
|||
|---|---|---|---|---|---| |
|||
| 1 | 「立即同步」+确认弹窗+同步进度弹窗(任务编号/进度 60%) | u76/u270-u314 | 发起同步(任务化) | POST /sync/dingtalk(同步阻塞,返 DtSyncResultDTO 计数) | ✅核心可用;**缺出参块**:任务编号、进度百分比(任务化改造,重接口——票 06 拍板本期边界) | |
|||
| 2 | 同步记录列表:筛选(任务编号/开始时间/触发方式/执行状态)+列(任务编号 SYNC-MMDD-序号/开始时间/触发方式/执行状态/部门变更/人员变更/异常数/详情)+分页 | u88-u135/u323 | 分页查询同步记录 | — | **缺接口**:GET /sync/tasks/page(需新建任务记录表) | |
|||
| 3 | 「详情」弹窗:执行结果/失败对象/接口错误/处理结果/进度/重新同步 | u285-u306/u328 | 任务详情 | — | **缺接口**:GET /sync/tasks/detail?id=;「重新同步」复用发起同步 | |
|||
| 4 | 同步设置区:自动同步启停/每日执行时间/重试规则(间隔≥1min、次数≥1)/并发规则/当前计划/下次执行/最近修改 | u230-u260/u331 | 设置查询+保存 | — | **缺接口**×2:GET/POST /sync/settings;需定时调度支持(重接口——票 06 拍板) | |
|||
|
|||
## 三、A7-2-1 角色管理(文本库 195 行) |
|||
|
|||
| # | 原型要素 | 证据 | 应有接口 | 现状 | 差距 | |
|||
|---|---|---|---|---|---| |
|||
| 1 | 顶部统计:角色总数/启用中/已停用/零使用人员角色数 | u23-u33/u204 | 角色统计 | — | **缺接口**:GET /roles/stats(或 page 附带统计块) | |
|||
| 2 | 筛选:角色名称(keyword)/角色类型/状态 | u35/u207/u204 | 分页查询 | POST /roles/page(RoleParam 仅继承 BaseParam:keyword✅) | **缺入参**:roleType(系统级/管理级/业务级/功能级)、status | |
|||
| 3 | 列表列:角色名称/角色类型/角色说明/在职使用人数/状态/最后更新 | u39-u58/u204 | — | RoleDTO(roleName/remark/updateTime✅) | **缺出参块**:roleType、status、userCount(在职使用人数,离职不计——u204 定义) | |
|||
| 4 | 新建角色弹窗:名称(2-30 唯一)/类型(必填单选)/说明 | u137-u146/u204 | 保存 | POST /roles/saveOrUpdate(roleName✅ remark✅) | **缺入参**:roleType;**校验差距**:名称长度/唯一性服务端校验 | |
|||
| 5 | 复制角色:来源角色+新名称,复制类型/说明/功能权限/数据范围/敏感权限,不复制人员,生成停用草稿 | u149-u160/u204 | 复制 | — | **缺接口**:POST /roles/copy(sourceRoleId+roleName) | |
|||
| 6 | 停用/启用角色(确认弹窗;启用校验:≥1 有效业务菜单权限+四域数据范围有效) | u163-u186/u204 | 状态切换 | — | **缺接口**:POST /roles/enable、/roles/disable(status 概念现缺) | |
|||
| 7 | 删除角色(仅在职使用人数=0;二次校验) | u189-u199/u204 | 删除 | POST /roles/delete(级联清理✅) | **校验差距**:使用人数=0 才可删的服务端校验 | |
|||
| 8 | 「处理使用人员」→ 跳组织与人员页按角色筛选 | u80/u204 | 用户列表按角色筛 | — | 同一(3)缺 roleId 入参(见一#3) | |
|||
| 9 | 处理使用人员弹窗:选择/姓名/所属部门/职位/当前参与商机数 | u281-u314 | 用户列表 | POST /users/page | 部分覆盖;「当前参与商机数」列为域内统计(挂账,低优先) | |
|||
|
|||
## 四、A7-2-2 编辑角色(基本信息)(文本库 83 行) |
|||
|
|||
| # | 原型要素 | 证据 | 应有接口 | 现状 | 差距 | |
|||
|---|---|---|---|---|---| |
|||
| 1 | 页头:角色编号/状态/在职使用人数/创建时间/最后更新 | u19-u54/u69 | 详情 | GET /roles/detail(RoleDTO:roleCode/createTime/updateTime✅) | **缺出参块**:status、userCount(同三#3) | |
|||
| 2 | 权限摘要(功能模块+数据范围只读) | u56-u63/u69 | 详情 | detail 返 resourceIds+moduleScopes | 前端可自算;资源名称需 resources/list 配合(可接受,不强求新端点) | |
|||
| 3 | 编辑基本信息(启用角色仅名称/说明可改;草稿可改类型) | u69 | 保存 | POST /roles/saveOrUpdate | **校验差距**:启用角色字段可改性校验(roleType 落地后) | |
|||
| 4 | 「保存为停用」按钮 | u266 | 保存 | saveOrUpdate | 依赖 status 概念(同三#6) | |
|||
|
|||
## 五、A7-2-3 编辑角色(功能权限)(文本库 110 行) |
|||
|
|||
| # | 原型要素 | 证据 | 应有接口 | 现状 | 差距 | |
|||
|---|---|---|---|---|---| |
|||
| 1 | 第二栏菜单树(按业务模块+已选数量) | u98-u125/u74 | 资源树 | GET /resources/list | ✅ | |
|||
| 2 | 第三栏权限点分组(搜索/仅看已选;「当前有效」=启用且上级启用) | u155/u74 | 资源树 | listAll 返全量含 status | ✅(前端过滤+派生「上级已停用」可接受) | |
|||
| 3 | 保存功能权限:一次提交全部菜单+权限点;服务端补齐祖先+校验菜单↔权限点依赖 | u74(3.2/3.6) | 保存授权 | POST /roles/assign-resources(祖先补全✅ ADR-0005) | **校验差距**:选权限点必须选所属菜单的依赖校验 | |
|||
| 4 | 取消模块权限二次确认+「当前影响:18 名使用人员」 | u23-u36/u74 | 影响人数 | — | 依赖三#3 userCount 出参 | |
|||
| 5 | 权限合并规则(多角色并集;仅启用角色计入) | u74(3.5) | 计算侧 | PermissionResolver(现有鉴权行为,不在本票深核) | 挂账:核对仅启用角色计入 | |
|||
|
|||
## 六、A7-2-4 编辑角色(数据范围)(文本库 58 行) |
|||
|
|||
| # | 原型要素 | 证据 | 应有接口 | 现状 | 差距 | |
|||
|---|---|---|---|---|---| |
|||
| 1 | 四域(线索/客户/商机/项目)×四档(仅本人/本部门/本部门及下属部门/全部数据);联系人跟随客户不单独配 | u27-u48/u54 | 模块清单+档位保存 | GET /api/data-scope/modules + detail.moduleScopes + saveOrUpdate.moduleScopesJson(档位 1-4 校验✅) | ✅(模块清单不含联系人即合规) | |
|||
| 2 | 缩小范围保存确认+影响人数 | u19/u54 | 影响人数 | — | 依赖三#3 userCount 出参 | |
|||
|
|||
## 七、A7-2-2 权限点管理(文本库 490 行) |
|||
|
|||
| # | 原型要素 | 证据 | 应有接口 | 现状 | 差距 | |
|||
|---|---|---|---|---|---| |
|||
| 1 | 筛选:名称模糊/编码模糊/状态(全部/启用/停用)+分页+命中补父级(父级不计入总数) | u25-u29/u197(3.1) | 树查询 | GET /resources/list(无参全量) | **缺入参**:name、code、status、current、size;补父级行为(服务端或前端实现待定) | |
|||
| 2 | 列表列:名称/类型/编码/路由路径/API URL/描述/状态/操作 | u235-u247/u197(3.2) | — | ResourceNodeDTO 字段全齐 | ✅ | |
|||
| 3 | 新增一级菜单:菜单形态(目录/页面)/名称/图标必填/编码/描述/路由(页面必填)/排序 | u379-u397/u200(4.2) | 保存 | POST /resources/saveOrUpdate(type=CATALOG/MENU、icon、perms、route、sort✅;perms 三类必填+全局唯一已实现——ResourceServiceImpl 注释引 v29 u200/u206) | **校验差距**:图标必填、路由页面必填校验;新增默认停用(u197 3.3-6,待核 service 现状) | |
|||
| 4 | 新增二级菜单(所属上级只读)/新增权限点(API URL 必填) | u427-u499/u200(4.3-4.4) | 保存 | saveOrUpdate(parentId、apiUrl✅) | ✅(apiUrl 必填校验待核) | |
|||
| 5 | 编辑:类型/编码只读;页面型一级有直挂权限点禁改目录 | u203 | 保存 | saveOrUpdate(编辑模式 perms 只读已实现) | ✅核心;「禁改目录」校验待核 | |
|||
| 6 | 独立「启用/停用」操作(确认弹窗带编码+角色引用数;被引用禁停用;停用菜单整棵下级暂时退出) | u118-u185/u208-u211 | 状态切换 | — | **缺接口**:POST /resources/enable、/resources/disable(含引用校验);现无独立端点 | |
|||
| 7 | 删除校验:仅停用可删;无下级;**有角色引用禁止删除**(展示引用角色清单:名称/状态/在职人数/前往配置) | u64-u101/u218-u219 | 删除 | POST /resources/delete(子节点检查✅;**级联清理引用**——与原型「禁止删除」语义相反) | **校验差距(语义相反)**:改为引用即阻止;「仅停用可删」校验 | |
|||
| 8 | 角色引用查询(删除/启停弹窗数据源) | u85-u98 | 引用清单 | — | **缺接口**:GET /resources/references?id=(返回引用角色列表) | |
|||
| 9 | 图标上传 | u626-u641 | 上传 | POST /resources/icon/upload | ✅ | |
|||
| 10 | 页面仅平台超管可访问 | u818/u191(2) | — | ResourceController 类级 hasRole('ADMIN') | ✅ | |
|||
|
|||
## 八、深 tag 对账(拍板④:核对存量端点挂「A7 后台管理/…」完整路径) |
|||
|
|||
| 端点 | 现挂 tag | 正式树路径 | 判定 | |
|||
|---|---|---|---| |
|||
| /users/* 4 端点 | A7 后台管理/用户管理 | A7 后台管理>A7-1 用户管理>A7-1-1 用户列表 | ✅(页面粒度:可细化 /用户管理/用户列表) | |
|||
| /depts/tree、save、delete | A7 后台管理/部门管理 | 正式树无「部门管理」页(部门树仅作 A7-1-1 左栏) | **tag 待修**+挂账:save/delete 原型无入口(对应未画的「组织架构」页 u67) | |
|||
| /sync/dingtalk、/users/admin-role | A7 后台管理/运维 | A7 后台管理>A7-1 用户管理>A7-1-2 同步任务 | **tag 待修**:sync 应挂「用户管理/同步任务」;admin-role 原型无对应页(挂账) | |
|||
| /roles/* 5 端点、/data-scope/modules | A7 后台管理/权限管理/角色管理 | A7 后台管理>A7-2 权限管理>A7-2-1 角色管理 | ✅ | |
|||
| /resources/* 4 端点 | A7 后台管理/权限点管理 | A7 后台管理>A7-2 权限管理>A7-2-2 权限点管理 | **tag 待修**:缺一级「权限管理」→「A7 后台管理/权限管理/权限点管理」 | |
|||
|
|||
## 九、缺口汇总(本分区) |
|||
|
|||
**缺接口(9)** |
|||
1. POST /users/batch-assign-roles —— 批量增量分配角色(A7-1-1) |
|||
2. 移交数据预览 + 移交执行(2 端点,跨域改 owner)(A7-1-1) |
|||
3. 用户列表导出(A7-1-1) |
|||
4. GET/POST /sync/settings + /sync/tasks/page + /sync/tasks/detail(3 端点,依赖任务化+调度,重接口)(A7-1-2) |
|||
5. GET /roles/stats(A7-2-1) |
|||
6. POST /roles/copy(A7-2-1) |
|||
7. POST /roles/enable + /roles/disable(A7-2-1) |
|||
8. POST /resources/enable + /resources/disable(A7-2-2 权限点) |
|||
9. GET /resources/references?id=(A7-2-2 权限点) |
|||
|
|||
**缺入参(3 项)** |
|||
- UserPageParam:+username、mobile、roleId、title(A7-1-1 筛选 6 项对齐) |
|||
- RoleParam:+roleType、status(A7-2-1 筛选) |
|||
- (RoleDTO 表单)+roleType(新建角色必填单选) |
|||
|
|||
**缺出参块(2 项)** |
|||
- UserStatsDTO:+lastSyncTime×2、lastTransferTime(统计卡片时间戳) |
|||
- RoleDTO/RoleParam 出参:+status、userCount、roleType(角色列表三列+A7-2 各弹窗「影响 N 人」数据源) |
|||
|
|||
**校验差距(4 项)** |
|||
- 角色名称 2-30 唯一;角色删除前使用人数=0;启用校验(≥1 业务菜单权限+四域数据范围);功能权限保存的菜单↔权限点依赖校验 |
|||
- 资源删除语义改写:有引用禁止(现级联清理,语义相反)+仅停用可删;启停带引用校验 |
|||
- 资源新增默认停用、图标/路由/apiUrl 必填校验(待核现状后补) |
|||
|
|||
**tag 待修(2 处)** |
|||
- /resources/* 补一级「权限管理」;/sync/* 改挂「用户管理/同步任务」(+dept/save、delete 挂账待拍板) |
|||
|
|||
**幻影/挂账(3 项)** |
|||
- /depts/save、/depts/delete:原型无入口(未画的「组织架构」页) |
|||
- /users/admin-role:原型无对应页 |
|||
- 职务下拉值域来源、处理使用人员弹窗「当前参与商机数」列 |
|||
@ -0,0 +1,73 @@ |
|||
# A7-3 下半逐页对比矩阵(票 04) |
|||
|
|||
范围:A7-3-2-4 项目查重(3 页)/ A7-3-2-5 公海与提醒(3 页)/ A7-3-2-6 商机相关字典 / A7-3-3 客户规则(2 页)/ A7-3-4 项目规则。对照 Controller:OpportunityPoolRule(8 端点)、CustomerReminderRule(2)、CustomerDedupRule(2)、crm-dict DictGroup(5)+ DictItem(8)。 |
|||
|
|||
## 一、A7-3-2-4 项目查重规则(3 页)——全缺码 |
|||
|
|||
| 原型页 | 页面元素 | 现状 | 缺口 | |
|||
|---|---|---|---| |
|||
| 列表页 | 查询:keyword(名称/编码/版本号)+ 适用范围下拉 + 状态下拉;列表 9 列(序号/名称/编码/版本/状态/适用范围/**执行次数**/最近更新/操作);操作矩阵同公海规则(草稿=详情/编辑/删除,发布中+停用=详情/编辑/复制) | 无 | 全缺码 | |
|||
| 详情页 | 头部(版本号/编码/适用范围/适用对象/状态/执行次数/是否默认/模板说明)+ 页签(概览/版本记录)+ 4 步骤向导只读 | 无 | 全缺码 | |
|||
| 新增/编辑页 | 基本信息(*规则名称/编码只读/*适用范围/适用对象[仅'对应项目属地'时]/是否默认[仅适用对象=全部时]/版本号只读/模板说明)+ 同一 4 步骤向导可编辑 + 保存草稿/保存并发布/取消 | 无 | 全缺码 | |
|||
|
|||
**4 步骤向导配置结构**(编辑页=详情页同构,DTO 设计素材): |
|||
|
|||
1. **触发场景**:触发场景多选(商机转项目/直接创建项目)+ 参与检测项目状态多选(进行中/已中止暂停/已关闭/已结项) |
|||
2. **关联项目检索**:条件行表(检索字段/数据来源/匹配方式[完全一致/名称相似]/相似度阈值/操作),默认 4 行=项目名称/项目区域/主要意向客户/甲方(各与自身比对),支持「+ 添加检索条件」 |
|||
3. **异常关系分析**:规则表(排序/条件表达式/输出研判结论/展开);条件表达式支持 且/或 + 括号嵌套(两层示例);研判结论枚举:明确重复/疑似重复/同商机多客户/跨商机同源冲突/一般风险标签提醒/无明显冲突 |
|||
4. **处理策略**:3 行固定(强制拦截/异常确认/正常创建)× 适用研判结论多选;系统动作文案平台固定 |
|||
|
|||
**端点设计素材**(版本化规则族,与 opp-stage-template / opp-pool-rule 同构): |
|||
`/api/rule/opp-dedup-rule` 下 page / detail / save-draft / publish / copy / disable / delete / versions 共 8 端点。 |
|||
DTO 要点:ruleCode(DUP_RULE_XX)/ruleName/versionNo/status(1/2/3)/applyScopeType(1 全部商机 2 按项目属地 3 按所属公司)/applyScopeValue(本地项目/南京公司…)/isDefault/ruleDesc + 4 步骤嵌套 JSON(triggerScenarios[]、projectStatuses[]、searchConditions[{field,source,matchMode,threshold}]、analysisRules[{seq,expression(嵌套且或组),conclusion}]、strategies{intercept[],confirm[],normal[]})。 |
|||
|
|||
**版本化+引用规则**(PRD 明确,实现必守):同族唯一草稿+唯一发布中;发布后原版转停用;推送规则引用查重规则时**锁定具体版本**(新版本发布后已有配置继续引用原版本);草稿不可被正式引用;执行次数按版本分别统计;提醒天数<回收天数。 |
|||
|
|||
## 二、A7-3-2-5 公海与提醒规则(3 页)——已实现,高度对齐 |
|||
|
|||
| 原型页 | 页面元素 | 现状 | 结论 | |
|||
|---|---|---|---| |
|||
| 列表页 | 查询三条件(keyword/适用范围/状态);列表 10 列含**自动回收/提前提醒**两专列;操作矩阵(草稿=详情/编辑/删除,发布中+停用=详情/编辑/复制);版本化同族规则 | OpportunityPoolRulePageParam(keyword+applyScope+status)✅;page ✅ | 对齐 | |
|||
| 详情页 | 基本信息(含**绑定商机:326 条**、是否默认、模板说明)+ 三配置区(进入公海/领取规则/提醒设置)+ 页签(概览/版本记录) | detail ✅;versions ✅;DTO 出参 ruleCode/ruleName/versionNo/status/applyScope/isDefault/allowManualPool/autoRecycleEnabled/recycleDays/allowFreeClaim/recycleRemindEnabled/remindDays/ruleDesc/deptIds/deptNames 全齐 | **缺出参 1 项:绑定商机数量** | |
|||
| 新增/编辑页 | 基本信息 + 三配置区 + 保存草稿/保存并发布/取消;联动:专用时部门必填、通用时可设默认、勾回收后天数必填、提醒天数<回收天数 | save-draft/publish/copy/disable/delete ✅;DTO 注释已含全部校验规则 | 对齐 | |
|||
|
|||
- 校验规则(PRD):回收天数>0;提醒天数>0 且 < 回收天数;未启用回收不可开提醒;仅通用规则可设默认且发布新默认自动取消原默认——服务层已实现(publish 注释:原发布中转停用、原默认取消默认、部门覆盖校验)✅ |
|||
- 业务口径备注(非接口):有效跟进=跟进记录更新/附件上传/字段编辑修订;商机执行规则时记录规则版本(历史记录不重算) |
|||
- **缺口**:detail 出参缺 `boundOpportunityCount`(依赖商机侧落 ruleVersion 引用字段,建议记 P2 待商机模块对齐后补) |
|||
|
|||
## 三、A7-3-2-6 商机相关字典(1 页)——crm-dict 能力完全覆盖,无缺码 |
|||
|
|||
| 页签 | 原型元素 | crm-dict 现状 | 结论 | |
|||
|---|---|---|---| |
|||
| 字典分组 | 列表 7 列(分组名称/编码/字典数量/排序号/状态/描述/操作:编辑/停用/删除)+ 新增/编辑弹窗(*分组名称/编码/排序号/描述/状态) | DictGroupController page/saveOrUpdate/delete/status/enabled-list;DictGroupDTO name/code/sortNo/status/description/builtin/**itemCount** | 覆盖 | |
|||
| 字典列表 | 列表 9 列(名称/编码/键值/分组/排序号/默认值/状态/描述/操作)+ 新增/编辑弹窗(*分组/*名称/编码/键值/排序号/默认值/描述/状态)+ 按 keyword/分组/状态筛选 | DictItemController page/saveOrUpdate/delete/force-delete/status/set-default/enabled-list/tree;DictItemDTO name/code/**value**/groupId/groupName/**isDefault**/**referenced**/**effectiveSelectable**/parentId(超集) | 覆盖 | |
|||
|
|||
- 业务规则对齐:编码分组内唯一、被引用禁删(referenced)、默认值同组唯一(set-default 自动取消原默认)、停用分组联动失活(effectiveSelectable)——全部有对应能力 ✅ |
|||
- **缺口仅为运营项**:①种子数据(4 分组:opportunity_stage 8 值 OPP_STAGE_01~、opportunity_status、opportunity_pause_reason 5 值 OPP_PAUSE_xx、opportunity_close_reason 6 值 OPP_CLOSE_xx,含「其他=填写补充说明」约定);②DictGroup/DictItem Controller 的 tag 挂「商机相关字典」多值 tags(与 A7-5 数据字典页共用,待票 05 核对后一并定);③前端页面复用现有端点(无后端工作) |
|||
|
|||
## 四、A7-3-3 客户规则(2 页)——已实现,完全对齐,无缺口 |
|||
|
|||
| 原型页 | 原型字段 | 现状 | 结论 | |
|||
|---|---|---|---| |
|||
| 超期未跟进提醒(A7-3-3-1,35 控件) | 总开关 + 首次触发时间(独立开关+天数,默认 30)+ 二次提醒间隔时间(独立开关+天数,默认 7)+ 保存/取消;全局配置模式;推送渠道钉钉+应用内 | CustomerReminderRuleDTO masterEnabled/firstTriggerEnabled/firstTriggerDays/secondIntervalEnabled/secondIntervalDays + GET current + POST save | 逐字段对齐 | |
|||
| 客户查重设置(A7-3-3-2,91 控件) | 总开关(仅控名称/电话)+ 客户名称(开关+精确/模糊+阈值档 70/80/90/自定义 0-100)+ 联系电话(开关+固定精确)+ 统一社会信用代码(强制精确、不可关闭、无配置项)+ 保存/取消 | CustomerDedupRuleDTO masterEnabled/nameEnabled/nameMatchMode/similarityThreshold(0-100)/phoneEnabled;信用代码无字段=正确(DTO 注释引 a7-3-3-2 §3);GET current + POST save | 逐字段对齐;70/80/90 为前端快捷档、落库仍是单一阈值 ✅ | |
|||
|
|||
## 五、A7-3-4 项目规则(1 页,多 tab)——全缺码 |
|||
|
|||
| 区块 | 原型元素 | 现状 | |
|||
|---|---|---| |
|||
| 阶段别名配置 | 7 阶段列表(序号/系统默认名/显示别名可编辑/说明),保存修改 | 无 | |
|||
| 项目拉群人员 | 7 角色列表(项目销售/设计师/报备专员/部门负责人/跟单员/财务专员/投标专员 × 是否拉入开关 + 说明),保存修改 | 无 | |
|||
| 冲突处理拉群规则 | 5 行(所有冲突方/报备专员/各方部门负责人/异地对接人[异地必须]/营销副总裁[条件触发] × 拉入规则 × 是否必须)+ 触发条件复选框(≥2 方自动触发/异地报备自动触发),保存修改 | 无 | |
|||
| 阶段提醒规则 | 8 行(阶段×提醒场景×触发条件×通知方式×启用开关;如冲突处理超时预警/投标倒计时/跟进断档等),保存修改。需求说明自注「配置入口,具体规则待后续补充」 | 无 | |
|||
| 标底认定规则(标底设定) | 9 标底类型(A+/A-/B+/B-/C/N/H/X/SQ 标)× 名称/说明/标底方%/中标方%/申请类型(发标后认定/需提前申请);修改仅影响新认定项目(提示条),保存修改 | 无 | |
|||
|
|||
**端点设计素材**(预期 `/api/rule/project-rule` 下):GET current(聚合 5 区块回显)+ POST 五个分区保存(stage-alias/save、pool-member/save、conflict-pull/save、stage-remind/save、bid-config/save),全量表单提交。归属模块(crm-rule vs 项目侧)为拍板项。 |
|||
|
|||
## 六、缺口汇总(票 04) |
|||
|
|||
**缺码(重)**:①项目查重规则模块(8 端点+DTO+4 步骤向导);②项目规则模块(current+5 分区保存)。 |
|||
**缺出参**:③公海规则 detail 缺绑定商机数量(P2,依赖商机侧引用字段)。 |
|||
**缺种子**:④商机相关字典 4 分组字典值。 |
|||
**tag 待修 3 处**(累计 10 处,详单见票 06):OpportunityPoolRule→「A7 后台管理/业务规则/商机规则/公海与提醒」;CustomerReminderRule→「…/业务规则/客户规则/客户管理设置(超期未跟进提醒)」;CustomerDedupRule→「…/业务规则/客户规则/客户管理设置(客户查重设置)」。 |
|||
**原型矛盾(拍板项)**:查重规则列头「执行次数」vs 字段说明/业务规则「引用次数」(被推送规则引用的次数)——建议按「引用次数」理解,执行=查重 job 实跑次数另计或合并展示。 |
|||
@ -0,0 +1,84 @@ |
|||
# 矩阵:A7-3 业务规则·上半(票 03) |
|||
|
|||
- 范围:A7-3-1 线索规则 + A7-3-2 商机规则上半(阶段设置 3 页 / 方案卡模板 3 页 / 方案推送规则 3 页),共 10 页。 |
|||
- 双源:文本库 6 文件 + 截图 10 张(阶段详情/编辑、推送详情/编辑 4 页文本库缺失,以截图为源——已读图提取)。 |
|||
- 类型标注同票 02。 |
|||
|
|||
## 一、A7-3-1 线索规则(= A2-1-5 引用副本,文本库 370 行) |
|||
|
|||
| # | 原型要素 | 证据 | 现状 | 差距 | |
|||
|---|---|---|---|---| |
|||
| 1 | 列表 13 列:NO./池名称/团队/部门/省份/负责市场(城市)/部门负责人/部门成员/领取规则/超时回收/失效时长/持有上限/操作 | u18-u43 | POST /api/rule/pool/page(LeadPoolDTO) | **缺出参块**:「部门成员」列无数据源(见 #4) | |
|||
| 2 | 按钮:新增公海池/批量删除/导入公海池/导出公海池 | u152/u154/u227/u228 | saveOrUpdate、delete-batch ✅ | **缺接口**×2:导入公海池、导出公海池 | |
|||
| 3 | 新增/编辑双 Tab(公海池+其他设置):名称/省份/负责市场(市-区-县多选组件 u431)/销售团队/销售部门/部门负责人/部门成员/部门协作人 + 领取规则(两档单选)/每日领取上限/持有上限/超时回收 N 天/失效 M 天 | u361-u431/u250-u269/u297 | LeadPoolDTO:poolName✅ provinceRegionIds✅ cityRegionIds✅(市/区) teamDeptId✅ deptId✅ ownerUserId✅ collaboratorUserIds✅ claimRule(1/2)✅ dailyClaimLimit✅ holdLimit✅ recycleDays✅ expireDays✅ | ✅ 字段高度对齐;**缺入参**:「部门成员」memberUserIds(原型独立多选,钉钉组织架构选人,u203-u224;现仅 owner+collaborator 两类,PoolMemberStore 落库 role_type 只有 OWNER/COLLABORATOR)——语义待拍板(显式成员表 vs 归属部门动态成员) | |
|||
| 4 | 部门负责人权限约束(超管全改/部门负责人限本部门/销售无入口) | u297 | savePool 已拦截非管理员改 deptId(P2-4) | ✅(其他规则参数的负责人可改性待核) | |
|||
| 5 | 双归属 tag | — | tags={"A2 线索管理/线索设置","A7 后台管理/线索规则"} | **tag 待修**:A7 侧应为「A7 后台管理/业务规则/线索规则」(v29 权威树:A7 后台管理>A7-3 业务规则>A7-3-1 线索规则);文档仓副本同步 | |
|||
|
|||
## 二、A7-3-2-1 商机阶段设置(3 页;详情/编辑页文本缺失,读图) |
|||
|
|||
| # | 原型要素 | 证据 | 现状 | 差距 | |
|||
|---|---|---|---|---| |
|||
| 1 | 列表 9 列:序号/模板名称/编码/版本号/状态/适用范围/最近更新/绑定商机/操作 | 列表 u30-u38 | page 按版本维度 ✅ | 「绑定商机(条数)」列:Controller 注释已裁决归商机域统计不回显——**已知裁决**,页面展示需数据源,建议票 06 重议(page 附 count 或前端另查) | |
|||
| 2 | 操作矩阵:草稿=详情/编辑/删除;发布中/停用=详情/编辑/复制 | u47/u56/u193 | page/detail/save-draft/publish/copy/disable/delete/versions 8 端点,状态机服务层兜底 ✅ | ✅ 高度对齐 | |
|||
| 3 | 版本规则:同模板唯一草稿+唯一发布中;发布后原版转停用;编辑发布中=生成新草稿;复制=独立新模板新编码 | u209 | saveDraft/publish/copy 语义吻合 ✅ | ✅ | |
|||
| 4 | 表单:模板名称/编码(系统)/适用范围/是否默认/模板说明 + 阶段流程节点条(增删排序) | 编辑页截图 | DTO:templateName✅ templateCode✅ applyScope(1/2) isDefault✅ templateDesc✅ nodes✅ | **缺入参/语义**:适用范围原型含条件式形态(列表示例「招标形式=ZC」「所属部门=广东15部」,u71/u89/u107),现有 applyScope 仅 1所有商机/2指定部门 两档,**缺「指定条件(如招标形式)」档** + 条件值字段 | |
|||
| 5 | 节点配置:阶段字典项(引用「商机阶段」字典)/自定义节点名称/工作目标;固定节点「已转项目」末位 | 编辑页截图+PRD 字段说明 9-11 | NodeItem:stageDictCode✅ customNodeName✅ workGoal✅ isFixed(服务端保证 OPP_STAGE_05)✅ | ✅ 完全对齐 | |
|||
| 6 | 字典项状态校验:「仅启用状态的字典项可供阶段模板新增时选择」 | 编辑页 PRD 字段说明 17 | — | **校验差距**:saveDraft/publish 校验 stageDictCode 引用字典项为启用态 | |
|||
| 7 | tag | — | @Tag("A7 后台管理/商机规则/阶段模板") | **tag 待修**:「A7 后台管理/业务规则/商机规则/商机阶段设置」 | |
|||
|
|||
## 三、A7-3-2-2 方案卡模板(3 页) |
|||
|
|||
| # | 原型要素 | 证据 | 现状 | 差距 | |
|||
|---|---|---|---|---| |
|||
| 1 | 列表 10 列:序号/模板名称/编码/版本号/状态/适用范围/**展示字段数/必填字段数**/最近更新/操作 | 列表 u339-u348 | page ✅(9 端点 + field-defs 系统字段库) | **缺出参块**:展示字段数/必填字段数两列无数据源(page 不回显字段项;detail 可算——建议 page 补两个 count) | |
|||
| 2 | 表单:*适用范围(1所有部门通用/2对应部门专用)+是否默认(仅通用可设·唯一) | 编辑页 u25/u28 | DTO applyScope 两档 + isDefault 约束 ✅(票 07 已按原型) | ✅ | |
|||
| 3 | 版本/操作矩阵(同阶段模板) | 列表 PRD | 同 #二-2 端点族 ✅ | ✅ | |
|||
| 4 | tag | — | @Tag("A7 后台管理/商机规则/方案卡模板") | **tag 待修**:「A7 后台管理/业务规则/商机规则/方案卡模板」 | |
|||
|
|||
## 四、A7-3-2-3 方案推送规则(3 页;详情/编辑页文本缺失,读图)——**全缺码模块** |
|||
|
|||
原型形态:版本化规则主体(同阶段/方案卡模板模式:唯一草稿+唯一发布中、发布转停用、编辑生成新草稿、复制独立新编码)+ **4 步骤推送配置器**。 |
|||
|
|||
**应有端点清单**(对标阶段模板 8 端点形态,/api/rule/opp-push-rule): |
|||
1. POST /page —— 分页(关键词/适用范围/状态筛选) |
|||
2. GET /detail?id= —— 详情(含步骤配置只读回显) |
|||
3. GET /versions?id= —— 同族版本列表 |
|||
4. POST /save-draft —— 保存草稿(配置全量替换) |
|||
5. POST /publish —— 保存并发布(原发布中转停用) |
|||
6. POST /copy?id= —— 复制(新编码 V1.0 草稿) |
|||
7. POST /disable?id= —— 停用(仅发布中) |
|||
8. POST /delete?id= —— 删除(仅草稿) |
|||
|
|||
**入参 DTO 设计素材**(编辑页截图+PRD 字段说明 16 项): |
|||
- 主体:ruleName(必填,同族同名单版本间不可重复)、ruleCode(系统生成 PUSH_RULE_XX)、versionNo/status(系统)、适用范围(**条件式**:「全部商机」或「指定项目阶段/商机阶段等」+条件值,列表示例「项目阶段='投标阶段'」)、是否默认(同千位可绑定的适用范围中设默认)、ruleDesc(选填) |
|||
- 推送配置 4 步骤: |
|||
1. 基础推送信息:推送节点名称(下拉)、方案卡模板引用(选商务场景后加载方案卡版本) |
|||
2. 字段校验:校验规则列表 [字段名称/字段来源(必填)/字段类型/校验规则(必填)/校验失败处理方式(必填)],可增删行;失败方式(阻断提交/跳过节点等) |
|||
3. 字段映射:映射列表 [字段名称/对应字段+推送方式] |
|||
4. 创建/关联项目:创建方式(自动创建/用户交互/关联已有项目)、项目重复规则引用、项目名称规则(默认+动态字段拼接)、字段获取项目目标、备注信息(支持客户/负责人/时间等变量占位) |
|||
- 出参附加:执行次数(按版本累计,草稿显示"--";执行侧归商机域,列表回显需统计源——票 06 拍板数据源) |
|||
- 业务约束(PRD u218):停用后保留累计次数不新增;历史执行记录关联原版本不迁移;草稿不参与推送判断 |
|||
- tag:「A7 后台管理/业务规则/商机规则/方案推送规则」 |
|||
|
|||
## 五、缺口汇总(本票) |
|||
|
|||
**缺接口(3 组)** |
|||
1. 公海池导入 + 导出(A7-3-1) |
|||
2. 方案推送规则全模块 8 端点(A7-3-2-3,新 Controller + 配置子表 + 推送执行侧归商机域另计) |
|||
3. (待议)阶段模板「绑定商机」/ 推送规则「执行次数」列表统计源 |
|||
|
|||
**缺入参(2 项)** |
|||
- LeadPoolDTO +「部门成员」memberUserIds(语义待拍板:显式成员表 vs 部门动态) |
|||
- 阶段模板 applyScope 条件式档(「指定条件(招标形式等)」+ 条件值字段)——与推送规则适用范围同构,建议统一「条件式适用范围」值对象 |
|||
|
|||
**缺出参块(2 项)** |
|||
- LeadPool 列表「部门成员」列数据源(随 #缺入参) |
|||
- 方案卡 page 出参 +展示字段数/必填字段数 |
|||
|
|||
**校验差距(1 项)** |
|||
- 阶段模板/推送规则保存时校验引用字典项为启用态 |
|||
|
|||
**tag 待修(3 处)** |
|||
- LeadPool 双归属副本 →「A7 后台管理/业务规则/线索规则」 |
|||
- 阶段模板 →「A7 后台管理/业务规则/商机规则/商机阶段设置」 |
|||
- 方案卡 →「A7 后台管理/业务规则/商机规则/方案卡模板」(+推送规则新端点按此格式) |
|||
@ -0,0 +1,56 @@ |
|||
# A7-4 日志管理 + A7-5 数据字典逐页对比矩阵(票 05) |
|||
|
|||
范围:A7-4-1 用户操作日志(175 控件)/ A7-4-2 登录日志(162)/ A7-4-3 批量操作日志(188)/ A7-5-1 数据字典(380)。预期:日志三页全缺码,数据字典对照 DictGroup/DictItem 共 13 端点。 |
|||
|
|||
## 一、A7-4 日志管理三页——全缺码(全局日志接口不存在) |
|||
|
|||
| 原型页 | 筛选条件 | 列表列 | 特有交互 | |
|||
|---|---|---|---| |
|||
| A7-4-1 用户操作日志 | 所属组织(模糊)/操作人(模糊)/时间范围(默认最近 7-30 天)/类型(全部/登录/查询/新增/修改/删除/处理/导入/导出) | 8 列:操作时间/操作人/所属组织/账号名称/操作IP地址/操作类型/操作内容/操作结果(成功/失败) | 时间倒序+分页 | |
|||
| A7-4-2 登录日志 | 所属组织/操作人/时间范围(默认 7 天)/类型(全部/登录/退出) | 7 列:操作时间/操作人/所属组织/账号名称/操作IP地址/状态/操作类型 | 同上 | |
|||
| A7-4-3 批量操作日志 | 所属组织/操作人/时间范围/状态(全部/成功/失败/**部分成功**) | 10 列:NO./操作时间/操作人/所属组织/账号名称/操作IP地址/操作类型(导入/导出/修改/删除)/**操作页面**/操作结果(含计数明细文本)/操作(下载) | ①行复选框+顶部「批量下载」打包下载结果文件;②单行「下载」按钮(导入错误报告/导出 Excel/批量修改删除明细);③结果文件保留 **90 天**,超期提示「文件已过期」 | |
|||
|
|||
三页权限口径一致:仅系统管理员及审计权限角色可见。 |
|||
|
|||
**端点设计素材**(`/api/log` 下,模块归属为拍板项): |
|||
- POST /operation/page —— OperationLogPageParam:deptName/operatorName/timeFrom/timeTo/opType(枚举 8 项) |
|||
- POST /login/page —— LoginLogPageParam:同上,opType 枚举(登录/退出) |
|||
- POST /batch/page —— BatchLogPageParam:同上,result(成功/失败/部分成功) |
|||
- POST /batch/download —— ids[] 打包下载结果文件 |
|||
- GET /batch/file?id= —— 单条结果文件下载(90 天有效期校验) |
|||
- 出参公共列:opTime/operatorName/deptName/account/ip/opType/content|page/result;写入侧(无页面):由采集机制落库 |
|||
|
|||
**实现形态决策素材**(现有域内日志实体映射,票 06 拍板): |
|||
- OpportunityOplog(oppId 轴):opKind/logType/entityName/fieldName/oldValue/newValue/bizRef/snapshotJson/opSource——服务商机详情轨迹页 |
|||
- CustomerOplog(customerId 轴):action(11 枚举)/detail/operatorId/operatorName/operatorDeptName 快照——服务客户详情轨迹页 |
|||
- LeadHistory(leadId 轴):opType(11 枚举)/detail(JSON)/opUserDeptName 快照——服务线索详情轨迹页 |
|||
- **三表共同缺口**:均无操作 IP、账号名称、全局统一操作类型(登录/查询/导入/导出…)、成功失败结果、操作页面字段;以业务 ID 为轴,无「按人/组织」全局审计轴 → 原型页面无法由现有表直接支撑 |
|||
- 方案 A:新全局日志表 + AOP/拦截器统一采集(域内三表保留继续服务详情页轨迹)——贴合原型、不动存量 DDL |
|||
- 方案 B:聚合三表 UNION 查询——需三表补列(IP/账号/结果/页面)、异构枚举映射复杂、跨库分页代价高 |
|||
- 依赖项:批量操作结果文件(导入错误报告/导出 Excel/批量修改明细)现状无统一文件落盘+保留期管理,方案 A 需一并设计文件存储与清理 |
|||
|
|||
## 二、A7-5 数据字典——无缺码,能力全覆盖 |
|||
|
|||
| 原型元素 | 现状 | 结论 | |
|||
|---|---|---| |
|||
| 字典分组页签(默认):查询(分组名称/编码模糊)+ 列表 7 列(名称/编码/**字典数量**/排序号/状态/描述/操作:编辑/停用/删除)+ 新增/编辑弹窗(*名称/*编码[创建后不可改]/排序号/描述/状态) | DictGroupController page/saveOrUpdate/delete/status/enabled-list;DictGroupDTO name/code/sortNo/status/description/builtin/**itemCount**(含启用+停用,与原型口径一致) | 覆盖 | |
|||
| 字典列表页签:查询(keyword/分组/状态)+ 列表 10 列(名称/编码/键值/**二级字典项**/分组名称/排序号/默认值/状态/描述/操作)+ 新增/编辑弹窗(*分组/*编码/排序号/描述/状态/*名称/*键值/默认值/**是否增加二级字典项**+*二级字典项) | DictItemController page/saveOrUpdate/delete/force-delete/status/set-default/enabled-list/tree;ItemPageParam groupId+status+keyword;DictItemDTO name/code/**value**/groupId/groupName/**isDefault**/**referenced**/**effectiveSelectable**/**parentId**(两级树超集) | 覆盖 | |
|||
| 业务规则:编码创建后不可改+服务端唯一;被引用禁删(提示「该字典已被引用,无法删除」);每分组最多一个启用默认、设新自动取消原默认;**默认项禁止停用**;停用分组→不能新建项+组内项不进选择器(自身可启用但提示暂不可用);历史数据回显原值标记已停用;二级项为独立字典行(独立编码)、两级联动 | referenced 实时计数、set-default 事务换默认、effectiveSelectable 失活标记、parentId+tree 两级树——机制全部具备 | 覆盖 | |
|||
| 排序规则:有排序号升序在前→无号排后→同号按创建时间 | 列表 orderBy 由 service 实现(顺带核过列表语义) | 覆盖 | |
|||
| 权限:菜单/页面/接口仅**平台超级管理员** | 现有细粒度权限点 @PreAuthorize(PERM_GROUP_*/PERM_ITEM_*)——种子仅授超管角色即等效,非代码缺口 | 备注 | |
|||
|
|||
两个验证点(执行票顺带核,不构成缺口):①「默认项禁止停用」服务层阻断校验是否已实现;②「未被引用才可改分组」编辑约束是否已实现(referenced 已有,UI 联动逻辑属前端)。 |
|||
|
|||
## 三、tag 对账(票 05 范围,累计 12 处) |
|||
|
|||
| Controller | 现状 tag | 待修 | |
|||
|---|---|---| |
|||
| DictGroupController | A7 后台管理/数据字典/分组 | 「A7 后台管理/系统设置/数据字典/分组」+ 方法级多值挂「A7 后台管理/业务规则/商机规则/商机相关字典」(A7-3-2-6 共用,ADR-0024) | |
|||
| DictItemController | A7 后台管理/数据字典/字典项 | 同上两组 | |
|||
|
|||
## 四、缺口汇总(票 05) |
|||
|
|||
- **缺码(重)**:日志管理 3 页 5 端点 + 全局日志表与采集机制(方案 A/B 票 06 拍板);批量操作结果文件落盘与 90 天保留期管理。 |
|||
- **tag 待修 2 处**(累计 12 处):crm-dict 两 Controller 补「系统设置」一级 + 商机相关字典多值 tags。 |
|||
- **无缺码**:A7-5 数据字典页(含二级字典项、默认值、引用校验全部命中现有实现)。 |
|||
- **拍板项**:日志实现形态(A 新表+AOP / B 聚合三表);批量操作日志是否本期交付(重接口边界)。 |
|||
@ -0,0 +1,44 @@ |
|||
# 票 11 bruno-sync tag 迁移:旧 tag 目录 -> 新 tag 目录(接口 .bru 逐字节复制,folder.bru 另由专用工具写入) |
|||
$ErrorActionPreference = 'Stop' |
|||
$root = 'E:\code\crm-api-docs' |
|||
|
|||
$dirs = @( |
|||
"$root\A7 后台管理\业务规则\商机规则\商机阶段设置", |
|||
"$root\A7 后台管理\业务规则\商机规则\方案卡模板", |
|||
"$root\A7 后台管理\业务规则\商机规则\公海与提醒", |
|||
"$root\A7 后台管理\业务规则\商机规则\商机相关字典", |
|||
"$root\A7 后台管理\业务规则\客户规则\客户管理设置(超期未跟进提醒)", |
|||
"$root\A7 后台管理\业务规则\客户规则\客户管理设置(客户查重设置)", |
|||
"$root\A7 后台管理\系统设置\数据字典\分组", |
|||
"$root\A7 后台管理\系统设置\数据字典\字典项" |
|||
) |
|||
foreach ($d in $dirs) { New-Item -ItemType Directory -Force -Path $d | Out-Null } |
|||
|
|||
$map = @( |
|||
@{ S='A7 后台管理\商机规则\阶段模板'; T='A7 后台管理\业务规则\商机规则\商机阶段设置' }, |
|||
@{ S='A7 后台管理\商机规则\方案卡模板'; T='A7 后台管理\业务规则\商机规则\方案卡模板' }, |
|||
@{ S='A7 后台管理\商机规则\公海规则'; T='A7 后台管理\业务规则\商机规则\公海与提醒' }, |
|||
@{ S='A7 后台管理\客户管理设置\超期未跟进提醒'; T='A7 后台管理\业务规则\客户规则\客户管理设置(超期未跟进提醒)' }, |
|||
@{ S='A7 后台管理\客户管理设置\查重设置'; T='A7 后台管理\业务规则\客户规则\客户管理设置(客户查重设置)' }, |
|||
@{ S='A7 后台管理\数据字典\分组'; T='A7 后台管理\系统设置\数据字典\分组' }, |
|||
@{ S='A7 后台管理\数据字典\字典项'; T='A7 后台管理\系统设置\数据字典\字典项' } |
|||
) |
|||
$n = 0 |
|||
foreach ($m in $map) { |
|||
Get-ChildItem -LiteralPath "$root\$($m.S)" -Filter '*.bru' | |
|||
Where-Object { $_.Name -ne 'folder.bru' } | |
|||
ForEach-Object { |
|||
Copy-Item -LiteralPath $_.FullName -Destination "$root\$($m.T)\$($_.Name)" |
|||
$n++ |
|||
} |
|||
} |
|||
# 商机相关字典副本:分组 5 接口 + 字典项 8 接口(同名同内容,skill tag 多挂点语义) |
|||
foreach ($g in @('分组','字典项')) { |
|||
Get-ChildItem -LiteralPath "$root\A7 后台管理\系统设置\数据字典\$g" -Filter '*.bru' | |
|||
Where-Object { $_.Name -ne 'folder.bru' } | |
|||
ForEach-Object { |
|||
Copy-Item -LiteralPath $_.FullName -Destination "$root\A7 后台管理\业务规则\商机规则\商机相关字典\$($_.Name)" |
|||
$n++ |
|||
} |
|||
} |
|||
Write-Output "copied=$n" |
|||
@ -0,0 +1,45 @@ |
|||
# 票 12 批 A:tag 改名导致的 12 个 .bru 搬移(DEL 清单全部为搬移源,无一真删除) |
|||
$ErrorActionPreference = 'Stop' |
|||
$root = 'E:\code\crm-api-docs' |
|||
|
|||
$dirs = @('A7 后台管理\权限管理\权限点管理', 'A7 后台管理\业务规则\线索规则', 'A7 后台管理\用户管理\同步任务') |
|||
foreach ($d in $dirs) { New-Item -ItemType Directory -Force -Path (Join-Path $root $d) | Out-Null } |
|||
|
|||
$moves = @( |
|||
@('A7 后台管理\权限点管理\资源树列表.bru', 'A7 后台管理\权限管理\权限点管理\资源树列表.bru'), |
|||
@('A7 后台管理\权限点管理\新增编辑资源节点.bru', 'A7 后台管理\权限管理\权限点管理\新增编辑资源节点.bru'), |
|||
@('A7 后台管理\权限点管理\删除资源节点.bru', 'A7 后台管理\权限管理\权限点管理\删除资源节点.bru'), |
|||
@('A7 后台管理\权限点管理\上传图标.bru', 'A7 后台管理\权限管理\权限点管理\上传图标.bru'), |
|||
@('A7 后台管理\线索规则\公海池分页列表.bru', 'A7 后台管理\业务规则\线索规则\公海池分页列表.bru'), |
|||
@('A7 后台管理\线索规则\公海池详情.bru', 'A7 后台管理\业务规则\线索规则\公海池详情.bru'), |
|||
@('A7 后台管理\线索规则\新建编辑公海池.bru', 'A7 后台管理\业务规则\线索规则\新建编辑公海池.bru'), |
|||
@('A7 后台管理\线索规则\删除公海池.bru', 'A7 后台管理\业务规则\线索规则\删除公海池.bru'), |
|||
@('A7 后台管理\线索规则\批量删除公海池.bru', 'A7 后台管理\业务规则\线索规则\批量删除公海池.bru'), |
|||
@('A7 后台管理\运维\钉钉组织同步.bru', 'A7 后台管理\用户管理\同步任务\钉钉组织同步.bru'), |
|||
@('A7 后台管理\部门管理\保存部门.bru', 'A7 后台管理\运维\保存部门.bru'), |
|||
@('A7 后台管理\部门管理\删除部门.bru', 'A7 后台管理\运维\删除部门.bru') |
|||
) |
|||
foreach ($m in $moves) { |
|||
if (Test-Path -LiteralPath (Join-Path $root $m[1])) { throw ('dest exists: ' + $m[1]) } |
|||
if (-not (Test-Path -LiteralPath (Join-Path $root $m[0]))) { throw ('src missing: ' + $m[0]) } |
|||
} |
|||
foreach ($m in $moves) { |
|||
Copy-Item -LiteralPath (Join-Path $root $m[0]) -Destination (Join-Path $root $m[1]) |
|||
if (-not (Test-Path -LiteralPath (Join-Path $root $m[1]))) { throw ('copy failed: ' + $m[1]) } |
|||
Remove-Item -LiteralPath (Join-Path $root $m[0]) -Force |
|||
} |
|||
Write-Output ('moved: ' + $moves.Count) |
|||
|
|||
foreach ($d in @('A7 后台管理\权限点管理', 'A7 后台管理\线索规则')) { |
|||
$full = Join-Path $root $d |
|||
if ((Test-Path -LiteralPath $full) -and -not (Get-ChildItem -LiteralPath $full)) { |
|||
Remove-Item -LiteralPath $full -Force |
|||
Write-Output ('rmdir: ' + $d) |
|||
} |
|||
} |
|||
Write-Output '--- ledger ---' |
|||
foreach ($d in @('A7 后台管理\权限管理\权限点管理', 'A7 后台管理\业务规则\线索规则', 'A7 后台管理\用户管理\同步任务', |
|||
'A7 后台管理\运维', 'A7 后台管理\部门管理')) { |
|||
$full = Join-Path $root $d |
|||
Write-Output ('{0,2} files: {1}' -f @(Get-ChildItem -LiteralPath $full).Count, $d) |
|||
} |
|||
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,803 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<title>A7-2-4 编辑角色(数据范围 )</title> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|||
<meta http-equiv="content-type" content="text/html; charset=utf-8"> |
|||
<link type="text/css" rel="stylesheet" data-src="resources/css/axure_rp_page.css"> |
|||
<link type="text/css" rel="stylesheet" data-src="data/styles.css"> |
|||
<link type="text/css" rel="stylesheet" data-src="files/a7-2-4_编辑角色(数据范围_)/styles.css"> |
|||
<style type="text/css"> |
|||
@font-face { |
|||
font-family: 'Axure Handwriting'; |
|||
font-style: normal; |
|||
font-weight: 400; |
|||
src: local('Axure Handwriting'), local('AxureHandwriting'), url('sketchfonts/AxureHandwriting.ttf') format('truetype'); |
|||
} |
|||
</style> |
|||
<style type="text/css"> |
|||
@font-face { |
|||
font-family: 'Axure Handwriting Bold'; |
|||
font-style: normal; |
|||
font-weight: 700; |
|||
src: local('Axure Handwriting Bold'), local('AxureHandwriting-Bold'), url('sketchfonts/AxureHandwriting-Bold.ttf') format('truetype'); |
|||
} |
|||
</style> |
|||
<style type="text/css"> |
|||
@font-face { |
|||
font-family: 'Axure Handwriting Italic'; |
|||
font-style: italic; |
|||
font-weight: 400; |
|||
src: local('Axure Handwriting Italic'), local('AxureHandwriting-Italic'), url('sketchfonts/AxureHandwriting-Italic.ttf') format('truetype'); |
|||
} |
|||
</style> |
|||
<style type="text/css"> |
|||
@font-face { |
|||
font-family: 'Axure Handwriting Bold Italic'; |
|||
font-style: italic; |
|||
font-weight: 700; |
|||
src: local('Axure Handwriting Bold Italic'), local('AxureHandwriting-BoldItalic'), url('sketchfonts/AxureHandwriting-BoldItalic.ttf') format('truetype'); |
|||
} |
|||
</style> |
|||
<script> |
|||
if (!window.$axure) { |
|||
window.$axure = {} |
|||
} |
|||
|
|||
if (!window.$axure.utils) { |
|||
window.$axure.utils = {} |
|||
} |
|||
if (!window.$axure.internal) { |
|||
window.$axure.internal = function() {} |
|||
} |
|||
</script><script data-src="resources/scripts/jquery-3.2.1.min.js"></script> |
|||
<script data-src="resources/scripts/axure/axQuery.js"></script> |
|||
<script data-src="resources/scripts/axure/globals.js"></script> |
|||
<script data-src="resources/scripts/axutils.js"></script> |
|||
<script data-src="resources/scripts/axure/annotation.js"></script> |
|||
<script data-src="resources/scripts/axure/axQuery.std.js"></script> |
|||
<script data-src="resources/scripts/axure/doc.js"></script> |
|||
<script data-src="resources/scripts/messagecenter.js"></script> |
|||
<script data-src="resources/scripts/axure/events.js"></script> |
|||
<script data-src="resources/scripts/axure/recording.js"></script> |
|||
<script data-src="resources/scripts/axure/action.js"></script> |
|||
<script data-src="resources/scripts/axure/expr.js"></script> |
|||
<script data-src="resources/scripts/axure/geometry.js"></script> |
|||
<script data-src="resources/scripts/axure/flyout.js"></script> |
|||
<script data-src="resources/scripts/axure/model.js"></script> |
|||
<script data-src="resources/scripts/axure/repeater.js"></script> |
|||
<script data-src="resources/scripts/axure/sto.js"></script> |
|||
<script data-src="resources/scripts/axure/utils.temp.js"></script> |
|||
<script data-src="resources/scripts/axure/variables.js"></script> |
|||
<script data-src="resources/scripts/axure/drag.js"></script> |
|||
<script data-src="resources/scripts/axure/move.js"></script> |
|||
<script data-src="resources/scripts/axure/visibility.js"></script> |
|||
<script data-src="resources/scripts/axure/style.js"></script> |
|||
<script data-src="resources/scripts/axure/adaptive.js"></script> |
|||
<script data-src="resources/scripts/axure/tree.js"></script> |
|||
<script data-src="resources/scripts/axure/init.temp.js"></script> |
|||
<script data-src="resources/scripts/axure/legacy.js"></script> |
|||
<script data-src="resources/scripts/axure/viewer.js"></script> |
|||
<script data-src="resources/scripts/axure/math.js"></script> |
|||
<script data-src="resources/scripts/axure/jquery.nicescroll.min.js"></script> |
|||
<script data-src="data/document.js"></script> |
|||
<script data-src="files/a7-2-4_编辑角色(数据范围_)/data.js"></script> |
|||
<script type="text/javascript"> |
|||
$axure.utils.getTransparentGifPath = function() { return 'resources/images/transparent.gif'; }; |
|||
$axure.utils.getOtherPath = function() { return 'resources/Other.html'; }; |
|||
$axure.utils.getReloadPath = function() { return 'resources/reload.html'; }; |
|||
</script> |
|||
<script> |
|||
function loadJS(url, callback){ |
|||
var script = document.createElement('script'); |
|||
var fn = callback || function(){}; |
|||
script.type = 'text/javascript'; |
|||
// IE |
|||
if (script.readyState) { |
|||
script.onreadystatechange = function(){ |
|||
if (script.readyState == 'loaded' || script.readyState == 'complete'){ |
|||
script.onreadystatechange = null; |
|||
fn(); |
|||
} |
|||
}; |
|||
} |
|||
else { |
|||
// Other Browser |
|||
script.onload = function() { |
|||
fn(); |
|||
}; |
|||
} |
|||
script.src = url; |
|||
script.async = false; |
|||
document.getElementsByTagName('head')[0].appendChild(script); |
|||
} |
|||
</script><script> |
|||
loadJS('//alistatic.lanhuapp.com/axureVersion.js?v=' + (Math.random()), function() { |
|||
// load css |
|||
var el = document.createElement("link"); |
|||
el.href = '//alistatic.lanhuapp.com/axureStyle.css?t='+(window.axureVersion || Math.random()); |
|||
el.async = false; |
|||
el.type = "text/css"; |
|||
el.rel = "stylesheet" |
|||
document.head.appendChild(el); |
|||
|
|||
// load js |
|||
var el = document.createElement("script"); |
|||
el.src = '//alistatic.lanhuapp.com/axureMapping.js?t='+(window.axureVersion || Math.random()); |
|||
el.async = false; |
|||
document.head.appendChild(el); |
|||
}) |
|||
</script></head> |
|||
<body style="display: none; opacity: 0;"> |
|||
<div id="base" class> |
|||
|
|||
<!-- Unnamed (通用页面-2) --> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u1" class="ax_default shape"> |
|||
<div id="u1_div" class></div> |
|||
<div id="u1_text" class="text "> |
|||
<p><span>`</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u2" class="ax_default box_1"> |
|||
<div id="u2_div" class></div> |
|||
<div id="u2_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u3" class="ax_default box_1"> |
|||
<img id="u3_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u3.svg"> |
|||
<div id="u3_text" class="text "> |
|||
<p><span>      itc信息化业务中台</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u4" class="ax_default box_2"> |
|||
<div id="u4_div" class></div> |
|||
<div id="u4_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (组合) --> |
|||
<div id="u5" class="ax_default" data-left="1317" data-top="21" data-width="111" data-height="24" layer-opacity="1"> |
|||
|
|||
<!-- Unnamed (图片 ) --> |
|||
<div id="u6" class="ax_default image"> |
|||
<img id="u6_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u6.jpg"> |
|||
<div id="u6_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u7" class="ax_default label"> |
|||
<div id="u7_div" class></div> |
|||
<div id="u7_text" class="text "> |
|||
<p><span>Panyu10109</span></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u8" class="ax_default placeholder2"> |
|||
<img id="u8_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u8.svg"> |
|||
<div id="u8_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u9" class="ax_default box_1"> |
|||
<img id="u9_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u9.svg"> |
|||
<div id="u9_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (组合) --> |
|||
<div id="u10" class="ax_default" data-left="1272" data-top="18" data-width="29" data-height="26" layer-opacity="1"> |
|||
|
|||
<!-- Unnamed (图片 ) --> |
|||
<div id="u11" class="ax_default image"> |
|||
<img id="u11_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u11.png"> |
|||
<div id="u11_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u12" class="ax_default box_2"> |
|||
<div id="u12_div" class></div> |
|||
<div id="u12_text" class="text "> |
|||
<p><span>16</span></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (组合) --> |
|||
<div id="u13" class="ax_default" data-left="1142" data-top="14" data-width="110" data-height="34" layer-opacity="1"> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u14" class="ax_default box_21"> |
|||
<img id="u14_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u14.svg"> |
|||
<div id="u14_text" class="text "> |
|||
<p><span>        AI助手</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (SVG) --> |
|||
<div id="u15" class="ax_default image1"> |
|||
<img id="u15_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u15.svg"> |
|||
<div id="u15_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<div id="u0" style="display:none; visibility:hidden;"></div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u16" class="ax_default _形状2"> |
|||
<div id="u16_div" class></div> |
|||
<div id="u16_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u17" class="ax_default _文本段落"> |
|||
<div id="u17_div" class></div> |
|||
<div id="u17_text" class="text "> |
|||
<p><span>权限管理 > 角色管理 > 销售总监</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u18" class="ax_default _形状2"> |
|||
<div id="u18_div" class></div> |
|||
<div id="u18_text" class="text "> |
|||
<p><span>编辑角色:销售总监</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u19" class="ax_default _形状2"> |
|||
<div id="u19_div" class></div> |
|||
<div id="u19_text" class="text "> |
|||
<p><span>数据范围缩小将在保存成功后立即影响当前 18 名使用人员。</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 保存范围 (矩形) --> |
|||
<div id="u20" class="ax_default _形状2" data-label="保存范围"> |
|||
<div id="u20_div" class></div> |
|||
<div id="u20_text" class="text "> |
|||
<p><span>保存数据范围</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- div (矩形) --> |
|||
<div id="u21" class="ax_default _形状2" data-label="div"> |
|||
<div id="u21_div" class></div> |
|||
<div id="u21_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u22" class="ax_default _形状2"> |
|||
<div id="u22_div" class></div> |
|||
<div id="u22_text" class="text "> |
|||
<p><span>基本信息</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u23" class="ax_default _形状2"> |
|||
<div id="u23_div" class></div> |
|||
<div id="u23_text" class="text "> |
|||
<p><span>功能权限</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 数据范围 (矩形) --> |
|||
<div id="u24" class="ax_default _形状2" data-label="数据范围"> |
|||
<div id="u24_div" class></div> |
|||
<div id="u24_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u25" class="ax_default _形状2"> |
|||
<div id="u25_div" class></div> |
|||
<div id="u25_text" class="text "> |
|||
<p><span>数据范围</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- div (矩形) --> |
|||
<div id="u26" class="ax_default _形状2" data-label="div"> |
|||
<div id="u26_div" class></div> |
|||
<div id="u26_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u27" class="ax_default _形状2"> |
|||
<div id="u27_div" class></div> |
|||
<div id="u27_text" class="text "> |
|||
<p><span>线索</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u28" class="ax_default _形状2"> |
|||
<div id="u28_div" class></div> |
|||
<div id="u28_text" class="text "> |
|||
<p><span>客户</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u29" class="ax_default _形状2"> |
|||
<div id="u29_div" class></div> |
|||
<div id="u29_text" class="text "> |
|||
<p><span>商机</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u30" class="ax_default _形状2"> |
|||
<div id="u30_div" class></div> |
|||
<div id="u30_text" class="text "> |
|||
<p><span>项目</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (线段) --> |
|||
<div id="u31" class="ax_default line1"> |
|||
<img id="u31_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u31.svg"> |
|||
<div id="u31_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (线段) --> |
|||
<div id="u32" class="ax_default line1"> |
|||
<img id="u32_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u31.svg"> |
|||
<div id="u32_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (线段) --> |
|||
<div id="u33" class="ax_default line1"> |
|||
<img id="u33_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u31.svg"> |
|||
<div id="u33_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单选按钮) --> |
|||
<div id="u34" class="ax_default radio_button1"> |
|||
<label id="u34_input_label" for="u34_input" style="position: absolute; left: 0px;"> |
|||
<img id="u34_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u34.svg"> |
|||
<div id="u34_text" class="text "> |
|||
<p><span>仅本人</span></p> |
|||
</div> |
|||
</label> |
|||
<input id="u34_input" type="radio" value="radio" name="u34"> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单选按钮) --> |
|||
<div id="u35" class="ax_default radio_button1"> |
|||
<label id="u35_input_label" for="u35_input" style="position: absolute; left: 0px;"> |
|||
<img id="u35_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u35.svg"> |
|||
<div id="u35_text" class="text "> |
|||
<p><span>仅本人</span></p> |
|||
</div> |
|||
</label> |
|||
<input id="u35_input" type="radio" value="radio" name="u35"> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单选按钮) --> |
|||
<div id="u36" class="ax_default radio_button1"> |
|||
<label id="u36_input_label" for="u36_input" style="position: absolute; left: 0px;"> |
|||
<img id="u36_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u36.svg"> |
|||
<div id="u36_text" class="text "> |
|||
<p><span>仅本人</span></p> |
|||
</div> |
|||
</label> |
|||
<input id="u36_input" type="radio" value="radio" name="u36"> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单选按钮) --> |
|||
<div id="u37" class="ax_default radio_button1"> |
|||
<label id="u37_input_label" for="u37_input" style="position: absolute; left: 0px;"> |
|||
<img id="u37_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u37.svg"> |
|||
<div id="u37_text" class="text "> |
|||
<p><span>仅本人</span></p> |
|||
</div> |
|||
</label> |
|||
<input id="u37_input" type="radio" value="radio" name="u37"> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单选按钮) --> |
|||
<div id="u38" class="ax_default radio_button1"> |
|||
<label id="u38_input_label" for="u38_input" style="position: absolute; left: 0px;"> |
|||
<img id="u38_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u38.svg"> |
|||
<div id="u38_text" class="text "> |
|||
<p><span>本部门</span></p> |
|||
</div> |
|||
</label> |
|||
<input id="u38_input" type="radio" value="radio" name="u38"> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单选按钮) --> |
|||
<div id="u39" class="ax_default radio_button1"> |
|||
<label id="u39_input_label" for="u39_input" style="position: absolute; left: 0px;"> |
|||
<img id="u39_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u39.svg"> |
|||
<div id="u39_text" class="text "> |
|||
<p><span>本部门</span></p> |
|||
</div> |
|||
</label> |
|||
<input id="u39_input" type="radio" value="radio" name="u39"> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单选按钮) --> |
|||
<div id="u40" class="ax_default radio_button1"> |
|||
<label id="u40_input_label" for="u40_input" style="position: absolute; left: 0px;"> |
|||
<img id="u40_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u40.svg"> |
|||
<div id="u40_text" class="text "> |
|||
<p><span>本部门</span></p> |
|||
</div> |
|||
</label> |
|||
<input id="u40_input" type="radio" value="radio" name="u40"> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单选按钮) --> |
|||
<div id="u41" class="ax_default radio_button1"> |
|||
<label id="u41_input_label" for="u41_input" style="position: absolute; left: 0px;"> |
|||
<img id="u41_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u41.svg"> |
|||
<div id="u41_text" class="text "> |
|||
<p><span>本部门</span></p> |
|||
</div> |
|||
</label> |
|||
<input id="u41_input" type="radio" value="radio" name="u41"> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单选按钮) --> |
|||
<div id="u42" class="ax_default radio_button1 selected"> |
|||
<label id="u42_input_label" for="u42_input" style="position: absolute; left: 0px;"> |
|||
<img id="u42_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u42_selected.svg"> |
|||
<div id="u42_text" class="text "> |
|||
<p><span>本部门及下属部门</span></p> |
|||
</div> |
|||
</label> |
|||
<input id="u42_input" type="radio" value="radio" name="u42" checked> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单选按钮) --> |
|||
<div id="u43" class="ax_default radio_button1 selected"> |
|||
<label id="u43_input_label" for="u43_input" style="position: absolute; left: 0px;"> |
|||
<img id="u43_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u43_selected.svg"> |
|||
<div id="u43_text" class="text "> |
|||
<p><span>本部门及下属部门</span></p> |
|||
</div> |
|||
</label> |
|||
<input id="u43_input" type="radio" value="radio" name="u43" checked> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单选按钮) --> |
|||
<div id="u44" class="ax_default radio_button1 selected"> |
|||
<label id="u44_input_label" for="u44_input" style="position: absolute; left: 0px;"> |
|||
<img id="u44_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u44_selected.svg"> |
|||
<div id="u44_text" class="text "> |
|||
<p><span>本部门及下属部门</span></p> |
|||
</div> |
|||
</label> |
|||
<input id="u44_input" type="radio" value="radio" name="u44" checked> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单选按钮) --> |
|||
<div id="u45" class="ax_default radio_button1"> |
|||
<label id="u45_input_label" for="u45_input" style="position: absolute; left: 0px;"> |
|||
<img id="u45_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u45.svg"> |
|||
<div id="u45_text" class="text "> |
|||
<p><span>本部门及下属部门</span></p> |
|||
</div> |
|||
</label> |
|||
<input id="u45_input" type="radio" value="radio" name="u45"> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单选按钮) --> |
|||
<div id="u46" class="ax_default radio_button1"> |
|||
<label id="u46_input_label" for="u46_input" style="position: absolute; left: 0px;"> |
|||
<img id="u46_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u46.svg"> |
|||
<div id="u46_text" class="text "> |
|||
<p><span>全部数据</span></p> |
|||
</div> |
|||
</label> |
|||
<input id="u46_input" type="radio" value="radio" name="u46"> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单选按钮) --> |
|||
<div id="u47" class="ax_default radio_button1"> |
|||
<label id="u47_input_label" for="u47_input" style="position: absolute; left: 0px;"> |
|||
<img id="u47_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u47.svg"> |
|||
<div id="u47_text" class="text "> |
|||
<p><span>全部数据</span></p> |
|||
</div> |
|||
</label> |
|||
<input id="u47_input" type="radio" value="radio" name="u47"> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单选按钮) --> |
|||
<div id="u48" class="ax_default radio_button1"> |
|||
<label id="u48_input_label" for="u48_input" style="position: absolute; left: 0px;"> |
|||
<img id="u48_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u48.svg"> |
|||
<div id="u48_text" class="text "> |
|||
<p><span>全部数据</span></p> |
|||
</div> |
|||
</label> |
|||
<input id="u48_input" type="radio" value="radio" name="u48"> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单选按钮) --> |
|||
<div id="u49" class="ax_default radio_button1"> |
|||
<label id="u49_input_label" for="u49_input" style="position: absolute; left: 0px;"> |
|||
<img id="u49_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u49.svg"> |
|||
<div id="u49_text" class="text "> |
|||
<p><span>全部数据</span></p> |
|||
</div> |
|||
</label> |
|||
<input id="u49_input" type="radio" value="radio" name="u49"> |
|||
</div> |
|||
|
|||
<!-- Unnamed (表格) --> |
|||
<div id="u50" class="ax_default"> |
|||
|
|||
<!-- Unnamed (单元格) --> |
|||
<div id="u51" class="ax_default table_cell1"> |
|||
<img id="u51_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u51.png"> |
|||
<div id="u51_text" class="text "> |
|||
<p><span>需求</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单元格) --> |
|||
<div id="u52" class="ax_default table_cell1"> |
|||
<img id="u52_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u52.png"> |
|||
<div id="u52_text" class="text "> |
|||
<p><span>需求说明</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单元格) --> |
|||
<div id="u53" class="ax_default table_cell1"> |
|||
<img id="u53_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u53.png"> |
|||
<div id="u53_text" class="text "> |
|||
<p><span>变更记录</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单元格) --> |
|||
<div id="u54" class="ax_default table_cell1"> |
|||
<img id="u54_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u54.png"> |
|||
<div id="u54_text" class="text "> |
|||
<p><span>4. 角色配置:数据范围</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单元格) --> |
|||
<div id="u55" class="ax_default table_cell1"> |
|||
<img id="u55_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u55.png"> |
|||
<div id="u55_text" class="text "> |
|||
<p><span>4.1 范围配置</span></p><p><span>1、分别为线索、客户、商机和招投标项目配置数据范围。联系人跟随所属客户的数据范围,不单独配置。</span></p><p><span>2、每个业务对象只能选择一种范围:</span></p><p><span>仅本人</span></p><p><span>本部门</span></p><p><span>本部门及下属部门</span></p><p><span>全部数据</span></p><p><span><br></span></p><p><span>3、页面中的部门均指钉钉部门。“仅本人”指员工本人作为负责人的数据。</span></p><p><span>4、数据范围只决定员工可以查看哪些数据,不自动授予编辑、删除、转移、导出或其他操作权限。</span></p><p><span>5、商机数据范围用于控制拥有商机管理菜单权限的员工可查看的团队商机。不扩大“销售机会”和“商机公海”的可见范围。</span></p><p><span><br></span></p><p><span><br></span></p><p><span>4.2 保存与失败处理</span></p><p><span>1、点击“保存数据范围”后,一次提交四类业务对象的数据范围。</span></p><p><span>2、保存成功后立即对当前角色关联的在职员工生效。</span></p><p><span>3、缩小启用角色的数据范围时,展示受影响的在职使用人数,并要求确认。</span></p><p><span>4、保存失败时:</span></p><p><span>本次修改全部不更新</span></p><p><span>页面保留当前编辑内容</span></p><p><span>已生效的数据范围保持不变</span></p><p><span>提供返回编辑和重新保存操作</span></p><p><span><br></span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单元格) --> |
|||
<div id="u56" class="ax_default table_cell1"> |
|||
<img id="u56_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u56.png"> |
|||
<div id="u56_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 取消 (矩形) --> |
|||
<div id="u57" class="ax_default _形状2" data-label="取消"> |
|||
<div id="u57_div" class></div> |
|||
<div id="u57_text" class="text "> |
|||
<p><span>返回</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (动态面板) --> |
|||
<div id="u58" class="ax_default"> |
|||
<div id="u58_state0" class="panel_state" data-label="State1" style> |
|||
<div id="u58_state0_content" class="panel_state_content"> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u59" class="ax_default box_2"> |
|||
<div id="u59_div" class></div> |
|||
<div id="u59_text" class="text "> |
|||
<p><span>权限管理</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u60" class="ax_default box_2"> |
|||
<div id="u60_div" class></div> |
|||
<div id="u60_text" class="text "> |
|||
<p><span>业务规则</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u61" class="ax_default box_2"> |
|||
<div id="u61_div" class></div> |
|||
<div id="u61_text" class="text "> |
|||
<p><span>日志管理</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u62" class="ax_default placeholder"> |
|||
<img id="u62_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u62.svg"> |
|||
<div id="u62_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u63" class="ax_default placeholder"> |
|||
<img id="u63_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u63.svg"> |
|||
<div id="u63_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u64" class="ax_default placeholder"> |
|||
<img id="u64_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u64.svg"> |
|||
<div id="u64_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (形状) --> |
|||
<div id="u65" class="ax_default box_1"> |
|||
<img id="u65_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u65.svg"> |
|||
<div id="u65_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (形状) --> |
|||
<div id="u66" class="ax_default box_1"> |
|||
<img id="u66_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u65.svg"> |
|||
<div id="u66_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (形状) --> |
|||
<div id="u67" class="ax_default box_1"> |
|||
<img id="u67_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u65.svg"> |
|||
<div id="u67_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u68" class="ax_default box_2"> |
|||
<div id="u68_div" class></div> |
|||
<div id="u68_text" class="text "> |
|||
<p><span>    角色权限</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u69" class="ax_default placeholder"> |
|||
<img id="u69_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u69.svg"> |
|||
<div id="u69_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u70" class="ax_default box_2"> |
|||
<div id="u70_div" class></div> |
|||
<div id="u70_text" class="text "> |
|||
<p><span>    权限点管理</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u71" class="ax_default placeholder"> |
|||
<img id="u71_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u71.svg"> |
|||
<div id="u71_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u72" class="ax_default box_2"> |
|||
<div id="u72_div" class></div> |
|||
<div id="u72_text" class="text "> |
|||
<p><span>用户管理</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u73" class="ax_default placeholder"> |
|||
<img id="u73_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u73.svg"> |
|||
<div id="u73_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (形状) --> |
|||
<div id="u74" class="ax_default box_1"> |
|||
<img id="u74_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u65.svg"> |
|||
<div id="u74_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u75" class="ax_default box_2"> |
|||
<div id="u75_div" class></div> |
|||
<div id="u75_text" class="text "> |
|||
<p><span>系统设置</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u76" class="ax_default placeholder"> |
|||
<img id="u76_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u76.svg"> |
|||
<div id="u76_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (形状) --> |
|||
<div id="u77" class="ax_default box_1"> |
|||
<img id="u77_img" class="img " data-src="images/a7-2-4_编辑角色(数据范围_)/u65.svg"> |
|||
<div id="u77_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u78" class="ax_default box_11"> |
|||
<div id="u78_div" class></div> |
|||
<div id="u78_text" class="text "> |
|||
<p><span>返回前台</span></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u79" class="ax_default box_2"> |
|||
<div id="u79_div" class></div> |
|||
<div id="u79_text" class="text "> |
|||
<p><span>    角色管理</span></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<script data-src="resources/scripts/axure/ios.js"></script> |
|||
</body> |
|||
</html> |
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,806 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<title>A7-3-3-1 客户管理设置(超期未跟进提醒)</title> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|||
<meta http-equiv="content-type" content="text/html; charset=utf-8"> |
|||
<link type="text/css" rel="stylesheet" data-src="resources/css/axure_rp_page.css"> |
|||
<link type="text/css" rel="stylesheet" data-src="data/styles.css"> |
|||
<link type="text/css" rel="stylesheet" data-src="files/a7-3-3-1_客户管理设置(超期未跟进提醒)/styles.css"> |
|||
<style type="text/css"> |
|||
@font-face { |
|||
font-family: 'Axure Handwriting'; |
|||
font-style: normal; |
|||
font-weight: 400; |
|||
src: local('Axure Handwriting'), local('AxureHandwriting'), url('sketchfonts/AxureHandwriting.ttf') format('truetype'); |
|||
} |
|||
</style> |
|||
<style type="text/css"> |
|||
@font-face { |
|||
font-family: 'Axure Handwriting Bold'; |
|||
font-style: normal; |
|||
font-weight: 700; |
|||
src: local('Axure Handwriting Bold'), local('AxureHandwriting-Bold'), url('sketchfonts/AxureHandwriting-Bold.ttf') format('truetype'); |
|||
} |
|||
</style> |
|||
<style type="text/css"> |
|||
@font-face { |
|||
font-family: 'Axure Handwriting Italic'; |
|||
font-style: italic; |
|||
font-weight: 400; |
|||
src: local('Axure Handwriting Italic'), local('AxureHandwriting-Italic'), url('sketchfonts/AxureHandwriting-Italic.ttf') format('truetype'); |
|||
} |
|||
</style> |
|||
<style type="text/css"> |
|||
@font-face { |
|||
font-family: 'Axure Handwriting Bold Italic'; |
|||
font-style: italic; |
|||
font-weight: 700; |
|||
src: local('Axure Handwriting Bold Italic'), local('AxureHandwriting-BoldItalic'), url('sketchfonts/AxureHandwriting-BoldItalic.ttf') format('truetype'); |
|||
} |
|||
</style> |
|||
<script> |
|||
if (!window.$axure) { |
|||
window.$axure = {} |
|||
} |
|||
|
|||
if (!window.$axure.utils) { |
|||
window.$axure.utils = {} |
|||
} |
|||
if (!window.$axure.internal) { |
|||
window.$axure.internal = function() {} |
|||
} |
|||
</script><script data-src="resources/scripts/jquery-3.2.1.min.js"></script> |
|||
<script data-src="resources/scripts/axure/axQuery.js"></script> |
|||
<script data-src="resources/scripts/axure/globals.js"></script> |
|||
<script data-src="resources/scripts/axutils.js"></script> |
|||
<script data-src="resources/scripts/axure/annotation.js"></script> |
|||
<script data-src="resources/scripts/axure/axQuery.std.js"></script> |
|||
<script data-src="resources/scripts/axure/doc.js"></script> |
|||
<script data-src="resources/scripts/messagecenter.js"></script> |
|||
<script data-src="resources/scripts/axure/events.js"></script> |
|||
<script data-src="resources/scripts/axure/recording.js"></script> |
|||
<script data-src="resources/scripts/axure/action.js"></script> |
|||
<script data-src="resources/scripts/axure/expr.js"></script> |
|||
<script data-src="resources/scripts/axure/geometry.js"></script> |
|||
<script data-src="resources/scripts/axure/flyout.js"></script> |
|||
<script data-src="resources/scripts/axure/model.js"></script> |
|||
<script data-src="resources/scripts/axure/repeater.js"></script> |
|||
<script data-src="resources/scripts/axure/sto.js"></script> |
|||
<script data-src="resources/scripts/axure/utils.temp.js"></script> |
|||
<script data-src="resources/scripts/axure/variables.js"></script> |
|||
<script data-src="resources/scripts/axure/drag.js"></script> |
|||
<script data-src="resources/scripts/axure/move.js"></script> |
|||
<script data-src="resources/scripts/axure/visibility.js"></script> |
|||
<script data-src="resources/scripts/axure/style.js"></script> |
|||
<script data-src="resources/scripts/axure/adaptive.js"></script> |
|||
<script data-src="resources/scripts/axure/tree.js"></script> |
|||
<script data-src="resources/scripts/axure/init.temp.js"></script> |
|||
<script data-src="resources/scripts/axure/legacy.js"></script> |
|||
<script data-src="resources/scripts/axure/viewer.js"></script> |
|||
<script data-src="resources/scripts/axure/math.js"></script> |
|||
<script data-src="resources/scripts/axure/jquery.nicescroll.min.js"></script> |
|||
<script data-src="data/document.js"></script> |
|||
<script data-src="files/a7-3-3-1_客户管理设置(超期未跟进提醒)/data.js"></script> |
|||
<script type="text/javascript"> |
|||
$axure.utils.getTransparentGifPath = function() { return 'resources/images/transparent.gif'; }; |
|||
$axure.utils.getOtherPath = function() { return 'resources/Other.html'; }; |
|||
$axure.utils.getReloadPath = function() { return 'resources/reload.html'; }; |
|||
</script> |
|||
<script> |
|||
function loadJS(url, callback){ |
|||
var script = document.createElement('script'); |
|||
var fn = callback || function(){}; |
|||
script.type = 'text/javascript'; |
|||
// IE |
|||
if (script.readyState) { |
|||
script.onreadystatechange = function(){ |
|||
if (script.readyState == 'loaded' || script.readyState == 'complete'){ |
|||
script.onreadystatechange = null; |
|||
fn(); |
|||
} |
|||
}; |
|||
} |
|||
else { |
|||
// Other Browser |
|||
script.onload = function() { |
|||
fn(); |
|||
}; |
|||
} |
|||
script.src = url; |
|||
script.async = false; |
|||
document.getElementsByTagName('head')[0].appendChild(script); |
|||
} |
|||
</script><script> |
|||
loadJS('//alistatic.lanhuapp.com/axureVersion.js?v=' + (Math.random()), function() { |
|||
// load css |
|||
var el = document.createElement("link"); |
|||
el.href = '//alistatic.lanhuapp.com/axureStyle.css?t='+(window.axureVersion || Math.random()); |
|||
el.async = false; |
|||
el.type = "text/css"; |
|||
el.rel = "stylesheet" |
|||
document.head.appendChild(el); |
|||
|
|||
// load js |
|||
var el = document.createElement("script"); |
|||
el.src = '//alistatic.lanhuapp.com/axureMapping.js?t='+(window.axureVersion || Math.random()); |
|||
el.async = false; |
|||
document.head.appendChild(el); |
|||
}) |
|||
</script></head> |
|||
<body style="display: none; opacity: 0;"> |
|||
<div id="base" class> |
|||
|
|||
<!-- Unnamed (通用页面-1) --> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u1" class="ax_default shape"> |
|||
<div id="u1_div" class></div> |
|||
<div id="u1_text" class="text "> |
|||
<p><span>`</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u2" class="ax_default box_1"> |
|||
<div id="u2_div" class></div> |
|||
<div id="u2_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u3" class="ax_default box_1"> |
|||
<img id="u3_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u3.svg"> |
|||
<div id="u3_text" class="text "> |
|||
<p><span>      itc业务中台</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u4" class="ax_default box_2"> |
|||
<div id="u4_div" class></div> |
|||
<div id="u4_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (组合) --> |
|||
<div id="u5" class="ax_default" data-left="1317" data-top="21" data-width="111" data-height="24" layer-opacity="1"> |
|||
|
|||
<!-- Unnamed (图片 ) --> |
|||
<div id="u6" class="ax_default image"> |
|||
<img id="u6_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u6.jpg"> |
|||
<div id="u6_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u7" class="ax_default label"> |
|||
<div id="u7_div" class></div> |
|||
<div id="u7_text" class="text "> |
|||
<p><span>Panyu10109</span></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u8" class="ax_default placeholder2"> |
|||
<img id="u8_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u8.svg"> |
|||
<div id="u8_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u9" class="ax_default box_1"> |
|||
<img id="u9_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u9.svg"> |
|||
<div id="u9_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u10" class="ax_default _形状2"> |
|||
<div id="u10_div" class></div> |
|||
<div id="u10_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u11" class="ax_default flow_shape1"> |
|||
<div id="u11_div" class></div> |
|||
<div id="u11_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u12" class="ax_default flow_shape1"> |
|||
<div id="u12_div" class></div> |
|||
<div id="u12_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (组合) --> |
|||
<div id="u13" class="ax_default" data-left="0" data-top="0" data-width="0" data-height="0" layer-opacity="1"> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u14" class="ax_default flow_shape1"> |
|||
<div id="u14_div" class></div> |
|||
<div id="u14_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u15" class="ax_default _默认样式" selectiongroup="u0标签页选项组4"> |
|||
<div id="u15_div" class></div> |
|||
<div id="u15_text" class="text "> |
|||
<p><span>客户查重设置</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u16" class="ax_default _默认样式" selectiongroup="u0标签页选项组4"> |
|||
<div id="u16_div" class></div> |
|||
<div id="u16_text" class="text "> |
|||
<p><span>超期未跟进提醒</span></p> |
|||
</div> |
|||
</div> |
|||
<div id="u0" style="display:none; visibility:hidden;"></div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u17" class="ax_default _二级标题"> |
|||
<div id="u17_div" class></div> |
|||
<div id="u17_text" class="text "> |
|||
<p><span>客户管理设置</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u18" class="ax_default _文本段落"> |
|||
<div id="u18_div" class></div> |
|||
<div id="u18_text" class="text "> |
|||
<p><span>客户 > 客户管理设置</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u19" class="ax_default _三级标题"> |
|||
<div id="u19_div" class></div> |
|||
<div id="u19_text" class="text "> |
|||
<p><span>超期未跟进提醒</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 开关 (动态面板) --> |
|||
<div id="u20" class="ax_default" data-label="开关"> |
|||
<div id="u20_state0" class="panel_state" data-label="State1" style> |
|||
<div id="u20_state0_content" class="panel_state_content"> |
|||
|
|||
<!-- 背景 (矩形) --> |
|||
<div id="u21" class="ax_default _默认样式" data-label="背景"> |
|||
<div id="u21_div" class></div> |
|||
<div id="u21_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 圆 (圆形) --> |
|||
<div id="u22" class="ax_default _默认样式" data-label="圆"> |
|||
<img id="u22_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/圆_u22.svg"> |
|||
<div id="u22_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u23" class="ax_default box_11"> |
|||
<div id="u23_div" class></div> |
|||
<div id="u23_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (组合) --> |
|||
<div id="u24" class="ax_default" data-left="589" data-top="298" data-width="92" data-height="16" layer-opacity="1"> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u25" class="ax_default box_21"> |
|||
<div id="u25_div" class></div> |
|||
<div id="u25_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u26" class="ax_default label1"> |
|||
<div id="u26_div" class></div> |
|||
<div id="u26_text" class="text "> |
|||
<p><span>首次触发时间</span></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (线段) --> |
|||
<div id="u27" class="ax_default line1"> |
|||
<img id="u27_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u27.svg"> |
|||
<div id="u27_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (精简底部) --> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u29" class="ax_default _默认样式"> |
|||
<img id="u29_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u29.svg"> |
|||
<div id="u29_text" class="text "> |
|||
<p><span>Copyright © </span><a id="u30" class="link" title="www.AxureUX.com"><span>www.AxureUX.com</span></a><span>, All Rights Reserved.</span></p><p><span>专业的交互原型素材原创分享平台</span></p> |
|||
</div> |
|||
</div> |
|||
<div id="u28" style="display:none; visibility:hidden;"></div> |
|||
|
|||
<!-- Unnamed (组合) --> |
|||
<div id="u31" class="ax_default" data-left="269" data-top="207" data-width="252" data-height="43" layer-opacity="1"> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u32" class="ax_default box_11"> |
|||
<div id="u32_div" class></div> |
|||
<div id="u32_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (形状) --> |
|||
<div id="u33" class="ax_default box_1"> |
|||
<img id="u33_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u33.svg"> |
|||
<div id="u33_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u34" class="ax_default box_11"> |
|||
<div id="u34_div" class></div> |
|||
<div id="u34_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (组合) --> |
|||
<div id="u35" class="ax_default" data-left="589" data-top="402" data-width="120" data-height="16" layer-opacity="1"> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u36" class="ax_default box_21"> |
|||
<div id="u36_div" class></div> |
|||
<div id="u36_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u37" class="ax_default label1"> |
|||
<div id="u37_div" class></div> |
|||
<div id="u37_text" class="text "> |
|||
<p><span>二次提醒间隔时间</span></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (组合) --> |
|||
<div id="u38" class="ax_default" data-left="597" data-top="323" data-width="89" data-height="40" layer-opacity="1"> |
|||
|
|||
<!-- Unnamed (文本框) --> |
|||
<div id="u39" class="ax_default text_field"> |
|||
<div id="u39_div" class></div> |
|||
<input id="u39_input" type="text" value class="u39_input"> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u40" class="ax_default box_11"> |
|||
<div id="u40_div" class></div> |
|||
<div id="u40_text" class="text "> |
|||
<p><span>▲</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u41" class="ax_default box_11"> |
|||
<div id="u41_div" class></div> |
|||
<div id="u41_text" class="text "> |
|||
<p><span>▼</span></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u42" class="ax_default label1"> |
|||
<div id="u42_div" class></div> |
|||
<div id="u42_text" class="text "> |
|||
<p><span>天</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 开关 (动态面板) --> |
|||
<div id="u43" class="ax_default" data-label="开关"> |
|||
<div id="u43_state0" class="panel_state" data-label="State1" style> |
|||
<div id="u43_state0_content" class="panel_state_content"> |
|||
|
|||
<!-- 背景 (矩形) --> |
|||
<div id="u44" class="ax_default _默认样式" data-label="背景"> |
|||
<div id="u44_div" class></div> |
|||
<div id="u44_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 圆 (圆形) --> |
|||
<div id="u45" class="ax_default _默认样式" data-label="圆"> |
|||
<img id="u45_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/圆_u22.svg"> |
|||
<div id="u45_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (组合) --> |
|||
<div id="u46" class="ax_default" data-left="597" data-top="427" data-width="89" data-height="40" layer-opacity="1"> |
|||
|
|||
<!-- Unnamed (文本框) --> |
|||
<div id="u47" class="ax_default text_field"> |
|||
<div id="u47_div" class></div> |
|||
<input id="u47_input" type="text" value class="u47_input"> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u48" class="ax_default box_11"> |
|||
<div id="u48_div" class></div> |
|||
<div id="u48_text" class="text "> |
|||
<p><span>▲</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u49" class="ax_default box_11"> |
|||
<div id="u49_div" class></div> |
|||
<div id="u49_text" class="text "> |
|||
<p><span>▼</span></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u50" class="ax_default label1"> |
|||
<div id="u50_div" class></div> |
|||
<div id="u50_text" class="text "> |
|||
<p><span>天</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 开关 (动态面板) --> |
|||
<div id="u51" class="ax_default" data-label="开关"> |
|||
<div id="u51_state0" class="panel_state" data-label="State1" style> |
|||
<div id="u51_state0_content" class="panel_state_content"> |
|||
|
|||
<!-- 背景 (矩形) --> |
|||
<div id="u52" class="ax_default _默认样式" data-label="背景"> |
|||
<div id="u52_div" class></div> |
|||
<div id="u52_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- 圆 (圆形) --> |
|||
<div id="u53" class="ax_default _默认样式" data-label="圆"> |
|||
<img id="u53_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/圆_u22.svg"> |
|||
<div id="u53_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (组合) --> |
|||
<div id="u54" class="ax_default" data-left="1171" data-top="851" data-width="233" data-height="55" layer-opacity="1"> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u55" class="ax_default primary_button"> |
|||
<div id="u55_div" class></div> |
|||
<div id="u55_text" class="text "> |
|||
<p><span>保存</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (形状) --> |
|||
<div id="u56" class="ax_default button"> |
|||
<img id="u56_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u56.svg"> |
|||
<div id="u56_text" class="text "> |
|||
<p><span>取消</span></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (线段) --> |
|||
<div id="u57" class="ax_default line1"> |
|||
<img id="u57_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u57.svg"> |
|||
<div id="u57_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (表格) --> |
|||
<div id="u58" class="ax_default"> |
|||
|
|||
<!-- Unnamed (单元格) --> |
|||
<div id="u59" class="ax_default table_cell1"> |
|||
<img id="u59_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u59.png"> |
|||
<div id="u59_text" class="text "> |
|||
<p><span>需求</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单元格) --> |
|||
<div id="u60" class="ax_default table_cell1"> |
|||
<img id="u60_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u60.png"> |
|||
<div id="u60_text" class="text "> |
|||
<p><span>需求说明</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单元格) --> |
|||
<div id="u61" class="ax_default table_cell1"> |
|||
<img id="u61_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u61.png"> |
|||
<div id="u61_text" class="text "> |
|||
<p><span>变更记录</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单元格) --> |
|||
<div id="u62" class="ax_default table_cell1"> |
|||
<img id="u62_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u62.png"> |
|||
<div id="u62_text" class="text "> |
|||
<p><span>超期未跟进提醒</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单元格) --> |
|||
<div id="u63" class="ax_default table_cell1"> |
|||
<img id="u63_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u63.png"> |
|||
<div id="u63_text" class="text "> |
|||
<p><span>功能说明</span></p><p><span>• 提供后台管理员配置客户超期未跟进提醒规则的入口,采用全局配置模式(非按阶段分别配置),仅后台管理面板可见。</span></p><p><span>• 页面顶部提供总开关,控制超期未跟进提醒功能的启用/禁用。</span></p><p><span>• 页面包含两个配置项:首次触发时间、二次提醒间隔时间。</span></p><p><span>• 首次触发时间:设置客户超过多少天未跟进时触发首次提醒,以天数为单位,默认30天。</span></p><p><span>• 二次提醒间隔时间:设置首次提醒后每隔多少天再次提醒,以天数为单位,默认7天。</span></p><p><span>• 每个配置项均提供独立的启用/禁用开关。</span></p><p><span><br></span></p><p><span>交互说明</span></p><p><span>• 点击顶部总开关可启用/禁用超期未跟进提醒功能,禁用后系统不再推送任何超期提醒。</span></p><p><span>• 首次触发时间和二次提醒间隔时间均提供数字输入框和增减按钮,支持输入自定义天数。</span></p><p><span>• 每个配置项的独立开关控制该项是否生效,关闭后该项不参与提醒计算。</span></p><p><span>• 提醒推送渠道为钉钉推送+应用内通知。</span></p><p><span>• 页面底部提供"取消"和"保存"按钮,点击保存后提交所有修改;点击取消放弃修改并恢复上次保存的配置。</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (单元格) --> |
|||
<div id="u64" class="ax_default table_cell1"> |
|||
<img id="u64_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u64.png"> |
|||
<div id="u64_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (动态面板) --> |
|||
<div id="u65" class="ax_default"> |
|||
<div id="u65_state0" class="panel_state" data-label="State1" style> |
|||
<div id="u65_state0_content" class="panel_state_content"> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u66" class="ax_default box_2"> |
|||
<div id="u66_div" class></div> |
|||
<div id="u66_text" class="text "> |
|||
<p><span>业务规则</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u67" class="ax_default box_2"> |
|||
<div id="u67_div" class></div> |
|||
<div id="u67_text" class="text "> |
|||
<p><span>权限管理</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u68" class="ax_default box_2"> |
|||
<div id="u68_div" class></div> |
|||
<div id="u68_text" class="text "> |
|||
<p><span>日志管理</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u69" class="ax_default placeholder"> |
|||
<img id="u69_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u69.svg"> |
|||
<div id="u69_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u70" class="ax_default placeholder"> |
|||
<img id="u70_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u70.svg"> |
|||
<div id="u70_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u71" class="ax_default placeholder"> |
|||
<img id="u71_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u71.svg"> |
|||
<div id="u71_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (形状) --> |
|||
<div id="u72" class="ax_default box_1"> |
|||
<img id="u72_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u72.svg"> |
|||
<div id="u72_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (形状) --> |
|||
<div id="u73" class="ax_default box_1"> |
|||
<img id="u73_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u72.svg"> |
|||
<div id="u73_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (形状) --> |
|||
<div id="u74" class="ax_default box_1"> |
|||
<img id="u74_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u72.svg"> |
|||
<div id="u74_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u75" class="ax_default box_2"> |
|||
<div id="u75_div" class></div> |
|||
<div id="u75_text" class="text "> |
|||
<p><span>    线索规则</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u76" class="ax_default placeholder"> |
|||
<img id="u76_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u76.svg"> |
|||
<div id="u76_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u77" class="ax_default box_2"> |
|||
<div id="u77_div" class></div> |
|||
<div id="u77_text" class="text "> |
|||
<p><span>    商机规则</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u78" class="ax_default placeholder"> |
|||
<img id="u78_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u78.svg"> |
|||
<div id="u78_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u79" class="ax_default box_2"> |
|||
<div id="u79_div" class></div> |
|||
<div id="u79_text" class="text "> |
|||
<p><span>用户管理</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u80" class="ax_default placeholder"> |
|||
<img id="u80_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u80.svg"> |
|||
<div id="u80_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (形状) --> |
|||
<div id="u81" class="ax_default box_1"> |
|||
<img id="u81_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u72.svg"> |
|||
<div id="u81_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u82" class="ax_default box_2"> |
|||
<div id="u82_div" class></div> |
|||
<div id="u82_text" class="text "> |
|||
<p><span>系统设置</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u83" class="ax_default placeholder"> |
|||
<img id="u83_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u83.svg"> |
|||
<div id="u83_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (形状) --> |
|||
<div id="u84" class="ax_default box_1"> |
|||
<img id="u84_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u72.svg"> |
|||
<div id="u84_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u85" class="ax_default box_11"> |
|||
<div id="u85_div" class></div> |
|||
<div id="u85_text" class="text "> |
|||
<p><span>返回前台</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u86" class="ax_default box_2"> |
|||
<div id="u86_div" class></div> |
|||
<div id="u86_text" class="text "> |
|||
<p><span>    客户规则</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u87" class="ax_default placeholder"> |
|||
<img id="u87_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u87.svg"> |
|||
<div id="u87_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u88" class="ax_default box_2"> |
|||
<div id="u88_div" class></div> |
|||
<div id="u88_text" class="text "> |
|||
<p><span>    项目规则</span></p> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (占位符) --> |
|||
<div id="u89" class="ax_default placeholder"> |
|||
<img id="u89_img" class="img " data-src="images/a7-3-3-1_客户管理设置(超期未跟进提醒)/u89.svg"> |
|||
<div id="u89_text" class="text " style="display:none; visibility: hidden"> |
|||
<p></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Unnamed (矩形) --> |
|||
<div id="u90" class="ax_default box_2"> |
|||
<div id="u90_div" class></div> |
|||
<div id="u90_text" class="text "> |
|||
<p><span>    客户规则</span></p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
<script data-src="resources/scripts/axure/ios.js"></script> |
|||
</body> |
|||
</html> |
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue