Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
X
xyw_asset_console
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DaiJiezhang
xyw_asset_console
Commits
00d54727
Commit
00d54727
authored
Jul 06, 2026
by
DaiJiezhang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refine phone list workspace
parent
da65cb92
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
235 additions
and
75 deletions
+235
-75
app-v2.js
app-v2.js
+2
-2
phone-add-dialog.js
src/modules/phone/phone-add-dialog.js
+9
-9
phone-detail-drawer.js
src/modules/phone/phone-detail-drawer.js
+1
-9
phone-list-runtime.js
src/modules/phone/phone-list-runtime.js
+137
-54
record-adapters.js
src/modules/shared/record-adapters.js
+7
-1
styles-v2.css
styles-v2.css
+79
-0
No files found.
app-v2.js
View file @
00d54727
...
...
@@ -75,7 +75,6 @@
channelOperator
:
'中国移动'
,
numberStatus
:
true
,
linkedWecom
:
'张三企业微信'
,
numberRetentionStatus
:
true
,
updateTime
:
'2024-03-12 10:25'
,
note
:
'用于客户联系'
}
...
...
@@ -529,7 +528,7 @@ function renderExternalRuntime(moduleKey) {
phoneText
:
{
add
:
'新增号卡'
,
reset
:
'重置'
,
searchPlaceholder
:
'搜索手机号、实名人或
城市
'
,
searchPlaceholder
:
'搜索手机号、实名人或
域名
'
,
deleteConfirm
:
'确认删除这条手机号记录吗?'
,
deleteFailed
:
'删除失败,请稍后重试'
,
loadFailed
:
'加载手机号列表失败,请确认本地后端已启动'
...
...
@@ -708,3 +707,4 @@ function initPage() {
window
.
updateActiveNav
=
updateActiveNav
;
window
.
renderModule
=
renderModule
;
document
.
addEventListener
(
'DOMContentLoaded'
,
initPage
);
src/modules/phone/phone-add-dialog.js
View file @
00d54727
...
...
@@ -107,31 +107,31 @@
/**
* 代码作用(白话):把外层传入的手机号记录回填到表单里,兼容列表记录和详情记录两种字段名,并把两张旧图按一个图片区域回显;关联文件:F:/Project/xyw_console/app-v2.js、F:/Project/xyw_console/src/modules/phone/phone-detail-drawer.js、F:/Project/xyw_console/src/modules/shared/record-adapters.js;关联逻辑(调用链/消息链/数据流):编辑按钮/详情抽屉编辑 -> PhoneAddDialogAPI.open('edit', record) -> populateFormData() -> 表单与图片预览回填。
*/
/**
* ???????????????????????????????? `card_status` / `mobile_status` / `channel_operator`?????????????????????F:/Project/xyw_console/src/modules/phone/phone-add-dialog.js?F:/Project/xyw_console/src/modules/shared/record-adapters.js?????????/???/???????/???? -> populateFormData() -> formData -> ?????
*/
function
populateFormData
(
record
)
{
formData
.
id
=
record
.
id
||
null
;
formData
.
phoneNumber
=
record
.
phoneNumber
||
record
.
phone
||
''
;
formData
.
realPerson
=
record
.
realPerson
||
''
;
formData
.
iccid
=
record
.
iccid
||
''
;
formData
.
city
=
record
.
city
||
''
;
formData
.
cardStatus
=
record
.
cardStatus
||
record
.
status
||
'正常'
;
formData
.
cardUsageLocation
=
record
.
cardUsageLocation
||
record
.
usageLocation
||
''
;
formData
.
cardStatus
=
record
.
cardStatus
||
record
.
card_status
||
record
.
status
||
'正常'
;
formData
.
cardUsageLocation
=
record
.
cardUsageLocation
||
record
.
card_usage_location
||
record
.
usageLocation
||
''
;
formData
.
wecom
=
record
.
wecom
===
true
;
formData
.
wechat
=
record
.
wechat
===
true
;
formData
.
outboundCall
=
record
.
outboundCall
===
true
||
record
.
outbound
===
'可外呼'
;
formData
.
outboundCall
=
record
.
outboundCall
===
true
||
record
.
outbound
_call
===
true
||
record
.
outbound
===
'可外呼'
;
formData
.
douyinAccount
=
record
.
douyinAccount
||
''
;
formData
.
miniProgramFiling
=
record
.
miniProgramFiling
===
true
;
formData
.
packageChange5yuan
=
record
.
packageChange5yuan
===
true
;
formData
.
channelOperator
=
record
.
channelOperator
||
record
.
carrier
||
''
;
formData
.
numberStatus
=
record
.
numberStatus
!==
fals
e
;
formData
.
linkedWecom
=
record
.
linkedWecom
||
''
;
formData
.
channelOperator
=
record
.
channelOperator
||
record
.
c
hannel_operator
||
record
.
c
arrier
||
''
;
formData
.
numberStatus
=
record
.
numberStatus
??
record
.
mobile_status
??
record
.
number_status
??
tru
e
;
formData
.
linkedWecom
=
record
.
linkedWecom
||
record
.
linked_wecom
||
''
;
imageItems
.
value
=
buildImageItemsFromRecord
(
record
);
syncImagesToFormData
();
}
/**
* 代码作用(白话):按新增或编辑模式打开手机号弹窗,并决定是重置表单还是回填旧记录;关联文件:F:/Project/xyw_console/app-v2.js、F:/Project/xyw_console/src/modules/phone/phone-add-dialog.js;关联逻辑(调用链/消息链/数据流):新增/编辑按钮 -> PhoneAddDialogAPI.open() -> open() -> visible/formData/imageItems 更新。
*/
function
open
(
mode
=
'add'
,
record
=
null
)
{
visible
.
value
=
true
;
isEdit
.
value
=
mode
===
'edit'
;
...
...
src/modules/phone/phone-detail-drawer.js
View file @
00d54727
(
function
initPhoneDetailDrawer
()
{
(
function
initPhoneDetailDrawer
()
{
const
{
createApp
,
ref
,
reactive
}
=
window
.
Vue
;
const
ElementPlus
=
window
.
ElementPlus
;
...
...
@@ -85,10 +85,6 @@
<span style="font-size: 15px; font-weight: 500; color: #111827;">{{ recordData.realPerson || '—' }}</span>
</div>
<div style="display: flex; flex-direction: column; gap: 6px;">
<span style="font-size: 13px; color: #6b7280;">ICCID</span>
<span style="font-size: 15px; font-weight: 500; color: #111827; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;">{{ recordData.iccid || '—' }}</span>
</div>
<div style="display: flex; flex-direction: column; gap: 6px;">
<span style="font-size: 13px; color: #6b7280;">归属地</span>
<span style="font-size: 15px; font-weight: 500; color: #111827;">{{ recordData.city || '—' }}</span>
</div>
...
...
@@ -122,10 +118,6 @@
<span style="font-size: 13px; color: #6b7280;">绑定企微号</span>
<span style="font-size: 15px; font-weight: 400; color: #374151;">{{ recordData.linkedWecom || '—' }}</span>
</div>
<div style="display: flex; flex-direction: column; gap: 6px;">
<span style="font-size: 13px; color: #6b7280;">抖音账号</span>
<span style="font-size: 15px; font-weight: 400; color: #374151;">{{ recordData.douyinAccount || '—' }}</span>
</div>
</div>
</section>
...
...
src/modules/phone/phone-list-runtime.js
View file @
00d54727
(
function
attachPhoneListRuntime
()
{
(
function
attachPhoneListRuntime
()
{
/**
* 代码作用(白话):把各种日期输入统一转成可比较的时间戳,方便手机号卡页面按更新时间筛选;关联文件:F:/Project/xyw_console/app-v2.js、F:/Project/xyw_console/src/modules/phone/phone-add-dialog.js;关联逻辑(调用链/消息链/数据流):表格记录.updatedAt -> toTimestamp() -> matchesDateRange() -> filteredRecords。
*/
...
...
@@ -74,6 +74,11 @@
const
filterStatus
=
ref
(
'all'
);
const
filterCarrier
=
ref
(
'all'
);
const
filterOutbound
=
ref
(
'all'
);
const
phonePrefix
=
ref
(
''
);
const
phoneLogic
=
ref
(
'and'
);
const
phoneSuffix
=
ref
(
''
);
const
showBasicFilter
=
ref
(
false
);
const
showPhoneSearch
=
ref
(
false
);
const
allRecordsCache
=
ref
([]);
const
loading
=
ref
(
false
);
const
multipleSelection
=
ref
([]);
...
...
@@ -123,11 +128,17 @@
/**
* 代码作用(白话):按状态、运营商、外呼能力、日期和关键词筛出当前应显示的手机号记录;关联文件:F:/Project/xyw_console/app-v2.js;关联逻辑(调用链/消息链/数据流):筛选控件 -> getFilteredRecords() -> totalFiltered()/visibleRows() -> 表格。
*/
/**
* ????????????????????????????????????????????????????????? `card_status` ??????????F:/Project/xyw_console/src/modules/phone/phone-list-runtime.js?F:/Project/xyw_console/src/modules/shared/record-adapters.js?????????/???/????????? -> getFilteredRecords() -> visibleRows -> ?????
*/
function
getFilteredRecords
()
{
let
result
=
allRecordsCache
.
value
.
slice
();
if
(
filterStatus
.
value
!==
'all'
)
{
result
=
result
.
filter
((
record
)
=>
record
.
status
===
filterStatus
.
value
);
result
=
result
.
filter
((
record
)
=>
{
const
cardStatus
=
record
.
cardStatus
||
record
.
card_status
||
record
.
status
;
return
cardStatus
===
filterStatus
.
value
;
});
}
if
(
filterCarrier
.
value
!==
'all'
)
{
...
...
@@ -140,6 +151,25 @@
result
=
result
.
filter
((
record
)
=>
matchesDateRange
(
record
,
filterDate
.
value
));
const
prefix
=
phonePrefix
.
value
.
trim
();
const
suffix
=
phoneSuffix
.
value
.
trim
();
if
(
prefix
||
suffix
)
{
result
=
result
.
filter
((
record
)
=>
{
const
phone
=
String
(
record
.
phone
||
''
);
const
matchPrefix
=
prefix
?
phone
.
startsWith
(
prefix
)
:
false
;
const
matchSuffix
=
suffix
?
phone
.
endsWith
(
suffix
)
:
false
;
if
(
prefix
&&
suffix
)
{
return
phoneLogic
.
value
===
'and'
?
(
matchPrefix
&&
matchSuffix
)
:
(
matchPrefix
||
matchSuffix
);
}
if
(
prefix
)
{
return
matchPrefix
;
}
return
matchSuffix
;
});
}
const
query
=
searchQuery
.
value
.
trim
().
toLowerCase
();
if
(
!
query
)
{
return
result
;
...
...
@@ -197,7 +227,21 @@
syncMountState
();
}
window
.
Vue
.
watch
([
filterStatus
,
filterCarrier
,
filterOutbound
,
filterDate
,
searchQuery
],
handleFilterStateChange
);
window
.
Vue
.
watch
([
filterStatus
,
filterCarrier
,
filterOutbound
,
filterDate
,
searchQuery
,
phonePrefix
,
phoneSuffix
,
phoneLogic
],
handleFilterStateChange
);
window
.
Vue
.
watch
(
phonePrefix
,
(
value
)
=>
{
const
cleaned
=
String
(
value
).
replace
(
/
[^
0-9
]
/g
,
''
).
slice
(
0
,
3
);
if
(
cleaned
!==
value
)
{
phonePrefix
.
value
=
cleaned
;
}
});
window
.
Vue
.
watch
(
phoneSuffix
,
(
value
)
=>
{
const
cleaned
=
String
(
value
).
replace
(
/
[^
0-9
]
/g
,
''
).
slice
(
0
,
4
);
if
(
cleaned
!==
value
)
{
phoneSuffix
.
value
=
cleaned
;
}
});
/**
* 代码作用(白话):把当前页码、分页大小和批量勾选状态存回壳层 mountState,保证切走再切回来还能恢复现场;关联文件:F:/Project/xyw_console/app-v2.js;关联逻辑(调用链/消息链/数据流):列表交互 -> syncMountState() -> moduleMountState.phone -> renderExternalRuntime('phone') 恢复。
...
...
@@ -218,8 +262,11 @@
/**
* 代码作用(白话):把不同状态映射成状态点颜色,让正常、异常、外呼能力等字段在列表里更直观;关联文件:F:/Project/xyw_console/app-v2.js;关联逻辑(调用链/消息链/数据流):status/wechatStatus/outbound -> getStatusClass() -> props.getPhoneStatusDotClass() -> status-dot class。
*/
function
getStatusClass
(
status
)
{
return
props
.
getPhoneStatusDotClass
(
status
);
/**
* ?????????????????????????? `card_status` ??????????????????F:/Project/xyw_console/app-v2.js?F:/Project/xyw_console/src/modules/phone/phone-list-runtime.js?????????/???/?????cardStatus -> getStatusClass() -> props.getPhoneStatusDotClass() -> status-dot class?
*/
function
getStatusClass
(
cardStatus
)
{
return
props
.
getPhoneStatusDotClass
(
cardStatus
);
}
/**
...
...
@@ -233,12 +280,15 @@
* 代码作用(白话):把手机号状态和号码保留状态统一翻译成业务文案,方便列表按库表字段直观看;关联文件:F:/Project/xyw_console/src/modules/shared/record-adapters.js;关联逻辑(调用链/消息链/数据流):normalizePhoneRecord() -> formatStatusText()/formatRetentionText() -> 状态列渲染。
*/
function
formatStatusText
(
value
)
{
if
(
value
===
false
||
value
===
0
||
value
===
'0'
||
value
===
'false'
||
value
===
'disabled'
||
value
===
'异常'
)
{
return
'异常'
;
}
if
(
value
===
true
||
value
===
1
||
value
===
'1'
||
value
===
'true'
||
value
===
'enabled'
||
value
===
'正常'
)
{
return
'正常'
;
}
return
value
?
'正常'
:
'异常'
;
}
/**
* 代码作用(白话):把号码保留布尔值翻译成“保留/注销”,避免业务同学自己推断 0 和 1;关联文件:F:/Project/xyw_console/src/modules/shared/record-adapters.js;关联逻辑(调用链/消息链/数据流):normalizePhoneRecord() -> formatRetentionText() -> 号码保留状态列。
*/
function
formatRetentionText
(
value
)
{
return
value
?
'保留'
:
'注销'
;
}
...
...
@@ -282,6 +332,11 @@
filterStatus
.
value
=
'all'
;
filterCarrier
.
value
=
'all'
;
filterOutbound
.
value
=
'all'
;
phonePrefix
.
value
=
''
;
phoneSuffix
.
value
=
''
;
phoneLogic
.
value
=
'and'
;
showBasicFilter
.
value
=
false
;
showPhoneSearch
.
value
=
false
;
currentPage
.
value
=
1
;
syncMountState
();
}
...
...
@@ -356,6 +411,7 @@
syncMountState
();
return
{
formatCellText
,
carrierOptions
,
outboundOptions
,
currentPage
,
...
...
@@ -377,6 +433,11 @@
filterStatus
,
filterCarrier
,
filterOutbound
,
phonePrefix
,
phoneLogic
,
phoneSuffix
,
showBasicFilter
,
showPhoneSearch
,
totalFiltered
,
totalPages
,
loading
,
...
...
@@ -390,51 +451,72 @@
},
template
:
`
<div class="table-area table-area-refined">
<div class="table-toolbar table-toolbar-refined">
<div class="table-toolbar table-toolbar-refined
phone-toolbar-main
">
<div class="toolbar-left">
<div class="toolbar-title-wrap">
<div class="toolbar-title">全部号卡 ({{ totalFiltered.toLocaleString('zh-CN') }})</div>
</div>
<div class="filter-selects filter-selects-refined" style="display: flex; align-items: center; gap: 8px;">
<el-select v-model="filterStatus" class="custom-fselect" style="width: 120px; height: 32px;">
<el-option label="状态:全部" value="all"></el-option>
<el-option v-for="label in phoneTableFilterLabels.filter((item) => item !== '全部')" :key="label" :label="label" :value="label"></el-option>
</el-select>
<el-select v-model="filterCarrier" class="custom-fselect" style="width: 140px; height: 32px;">
<el-option label="运营商:全部" value="all"></el-option>
<el-option v-for="carrier in carrierOptions" :key="carrier" :label="carrier" :value="carrier"></el-option>
</el-select>
<el-select v-model="filterOutbound" class="custom-fselect" style="width: 150px; height: 32px;">
<el-option label="外呼:全部" value="all"></el-option>
<el-option v-for="outbound in outboundOptions" :key="outbound" :label="outbound" :value="outbound"></el-option>
</el-select>
<el-date-picker
v-model="filterDate"
type="daterange"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
style="width: 240px; height: 32px;"
></el-date-picker>
<el-input
v-model="searchQuery"
:placeholder="phoneText.searchPlaceholder"
clearable
style="width: 260px; height: 32px;"
>
<template #prefix>
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/></svg>
</template>
</el-input>
</div>
</div>
<div class="toolbar-right">
<div class="toolbar-primary-actions">
<button class="btn btn-primary" type="button" @click="handleAdd" style="height: 32px; padding: 0 16px;">{{ phoneText.add }}</button>
</div>
<div class="toolbar-right phone-toolbar-actions">
<button type="button" class="filter-toggle-btn" :class="{ 'is-active': showBasicFilter }" @click="showBasicFilter = !showBasicFilter">基础筛选</button>
<button type="button" class="filter-toggle-btn" :class="{ 'is-active': showPhoneSearch }" @click="showPhoneSearch = !showPhoneSearch">号码搜索</button>
<el-input
v-model="searchQuery"
:placeholder="phoneText.searchPlaceholder"
clearable
class="phone-search-input"
style="width: 220px; height: 32px;"
>
<template #prefix>
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="M21 21l-4.35-4.35"/></svg>
</template>
</el-input>
<button class="btn btn-primary" type="button" @click="handleAdd" style="height: 32px; padding: 0 16px;">{{ phoneText.add }}</button>
<button class="btn-reset btn-reset-refined" type="button" @click="resetTableState">{{ phoneText.reset }}</button>
</div>
</div>
<div v-if="showBasicFilter" class="phone-filter-row">
<el-select v-model="filterStatus" class="custom-fselect" style="width: 120px;">
<el-option label="状态:全部" value="all"></el-option>
<el-option v-for="label in phoneTableFilterLabels.filter((item) => item !== '全部')" :key="label" :label="label" :value="label"></el-option>
</el-select>
<el-select v-model="filterCarrier" class="custom-fselect" style="width: 140px;">
<el-option label="运营商:全部" value="all"></el-option>
<el-option v-for="carrier in carrierOptions" :key="carrier" :label="carrier" :value="carrier"></el-option>
</el-select>
<el-select v-model="filterOutbound" class="custom-fselect" style="width: 150px;">
<el-option label="外呼:全部" value="all"></el-option>
<el-option v-for="outbound in outboundOptions" :key="outbound" :label="outbound" :value="outbound"></el-option>
</el-select>
<el-date-picker
v-model="filterDate"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
class="phone-date-range"
></el-date-picker>
</div>
<div v-if="showPhoneSearch" class="phone-filter-row">
<el-input
v-model="phonePrefix"
placeholder="前3位"
maxlength="3"
clearable
style="width: 90px;"
></el-input>
<el-select v-model="phoneLogic" style="width: 72px;">
<el-option label="与" value="and"></el-option>
<el-option label="或" value="or"></el-option>
</el-select>
<el-input
v-model="phoneSuffix"
placeholder="后4位"
maxlength="4"
clearable
style="width: 100px;"
></el-input>
</div>
<div class="table-wrap table-wrap-refined" v-loading="loading">
<el-table
ref="multipleTableRef"
...
...
@@ -443,8 +525,8 @@
style="width: 100%"
class="domain-table domain-table-refined"
@selection-change="handleSelectionChange"
:header-cell-style="{ background: '
#fafafa', color: '#4b5563', fontWeight: 500, padding: '12px 20px', borderBottom: '1px solid #f3f4f6
' }"
:cell-style="{ padding: '1
2
px 20px', borderBottom: '1px solid #f3f4f6', color: '#111827', whiteSpace: 'nowrap' }"
:header-cell-style="{ background: '
linear-gradient(180deg, #f9fafb 0%, #f3f4f6 100%)', color: '#374151', fontWeight: 600, padding: '14px 20px', borderBottom: '1px solid #e5e7eb
' }"
:cell-style="{ padding: '1
4
px 20px', borderBottom: '1px solid #f3f4f6', color: '#111827', whiteSpace: 'nowrap' }"
>
<el-table-column type="selection" width="50" fixed="left" />
<el-table-column label="图片" min-width="160">
...
...
@@ -456,7 +538,7 @@
<div style="display: none; align-items: center; justify-content: center; width: 100%; height: 100%; font-size: 11px; color: #94a3b8; background: #f8fafc;">占位图</div>
</div>
</template>
<div v-else style="width: 52px; height: 52px; border-radius: 10px; border: 1px dashed #cbd5e1; background:
#f8fafc
; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #94a3b8; flex: 0 0 auto;">占位图</div>
<div v-else style="width: 52px; height: 52px; border-radius: 10px; border: 1px dashed #cbd5e1; background:
linear-gradient(135deg, #f8fafc 0%, #f1f5f9 100%)
; display: flex; align-items: center; justify-content: center; font-size: 11px; color: #94a3b8; flex: 0 0 auto;">占位图</div>
</div>
</template>
</el-table-column>
...
...
@@ -465,11 +547,12 @@
<a href="#" class="domain-link" @click.prevent="focusRow(scope.row.id)">{{ scope.row.phone || '-' }}</a>
</template>
</el-table-column>
<el-table-column label="
真实联系
人" min-width="150">
<el-table-column label="
实名
人" min-width="150">
<template #default="scope">
<span :title="scope.row.realPerson || '-'" style="display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">{{ formatCellText(scope.row.realPerson) }}</span>
</template>
</el-table-column>
<el-table-column label="ICCID" min-width="220">
<template #default="scope">
<span :title="scope.row.iccid || '-'" style="display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">{{ formatCellText(scope.row.iccid) }}</span>
...
...
@@ -483,8 +566,8 @@
<el-table-column label="号卡状态" min-width="120">
<template #default="scope">
<span class="status-chip-wrap">
<span class="status-dot" :class="getStatusClass(scope.row.status)"></span>
<span>{{ scope.row.status }}</span>
<span class="status-dot" :class="getStatusClass(scope.row.
cardStatus || scope.row.card_status || scope.row.
status)"></span>
<span>{{ scope.row.
cardStatus || scope.row.card_status || scope.row.
status }}</span>
</span>
</template>
</el-table-column> <el-table-column label="企业微信" min-width="110">
...
...
@@ -510,8 +593,8 @@
<span :title="scope.row.channelOperator || '-'" style="display: inline-block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;">{{ formatCellText(scope.row.channelOperator) }}</span>
</template>
</el-table-column>
<el-table-column label="
手机号
状态" min-width="120">
<template #default="scope">{{ formatStatusText(scope.row.numberStatus) }}</template>
<el-table-column label="
号码
状态" min-width="120">
<template #default="scope">{{ formatStatusText(scope.row.numberStatus
?? scope.row.mobile_status ?? scope.row.number_status
) }}</template>
</el-table-column>
<el-table-column label="绑定企业微信" min-width="180">
<template #default="scope">
...
...
@@ -520,7 +603,7 @@
</el-table-column> <el-table-column label="操作" width="100" fixed="right">
<template #default="scope">
<div class="action-cluster" style="display: flex; flex-direction: column; align-items: flex-start; gap: 8px;">
<button class="action-pill action-pill-primary" type="button" @click.stop="handleRowAction('view', scope.row.id)" style="border: none; background: transparent;
color: #2563eb
; cursor: pointer; padding: 0; font-weight: 600; line-height: 1;">查看</button>
<button class="action-pill action-pill-primary" type="button" @click.stop="handleRowAction('view', scope.row.id)" style="border: none; background: transparent;
background-image: linear-gradient(90deg, #2563eb, #60a5fa); -webkit-background-clip: text; -webkit-text-fill-color: transparent
; cursor: pointer; padding: 0; font-weight: 600; line-height: 1;">查看</button>
<button class="action-pill" type="button" @click.stop="handleRowAction('edit', scope.row.id)" style="border: none; background: transparent; color: #4b5563; cursor: pointer; padding: 0; font-weight: 500; line-height: 1;">编辑</button>
<button class="action-pill" type="button" @click.stop="handleRowAction('delete', scope.row.id)" style="border: none; background: transparent; color: #ef4444; cursor: pointer; padding: 0; font-weight: 500; line-height: 1;">删除</button>
</div>
...
...
src/modules/shared/record-adapters.js
View file @
00d54727
...
...
@@ -83,11 +83,16 @@
/**
* 代码作用(白话):把手机号原始记录整理成列表、详情抽屉、编辑弹窗共用的统一字段,避免每个组件自己猜字段名;关联文件:F:/Project/xyw_console/app-v2.js、F:/Project/xyw_console/src/modules/phone/phone-list-runtime.js、F:/Project/xyw_console/src/modules/phone/phone-detail-drawer.js、F:/Project/xyw_console/src/modules/phone/phone-add-dialog.js;关联逻辑(调用链/消息链/数据流):PhoneApiClient/DATA_SOURCES.phone -> normalizePhoneRecord() -> app-v2.js 注入 -> 手机号列表/详情/编辑弹窗。
*/
/**
* ????????????????????????????????????????????? status ??????????????F:/Project/xyw_console/src/modules/shared/record-adapters.js?F:/Project/xyw_console/src/modules/phone/phone-list-runtime.js?F:/Project/xyw_console/src/modules/phone/phone-add-dialog.js?????????/???/????????? -> normalizePhoneRecord() -> ??/??/?????
*/
function
normalizePhoneRecord
(
row
)
{
const
source
=
row
||
{};
const
images
=
buildPhoneImages
(
source
);
const
cardStatusRaw
=
source
.
cardStatus
??
source
.
card_status
??
source
.
status
;
const
cardStatus
=
cardStatusRaw
===
0
||
cardStatusRaw
===
'0'
||
cardStatusRaw
===
'异常'
?
'异常停机'
:
(
cardStatusRaw
||
'正常'
);
const
cardStatus
=
cardStatusRaw
===
0
||
cardStatusRaw
===
'0'
||
cardStatusRaw
===
'异常'
?
'异常停机'
:
(
cardStatusRaw
||
'正常'
);
const
phoneNumber
=
source
.
phoneNumber
||
source
.
phone_number
||
source
.
phone
||
''
;
const
realPerson
=
source
.
realPerson
||
source
.
real_person
||
''
;
const
channelOperator
=
source
.
channelOperator
||
source
.
channel_operator
||
source
.
carrier
||
''
;
...
...
@@ -148,6 +153,7 @@
packageChange5yuan
:
packageChangeEnabled
,
package_change_5yuan
:
packageChangeEnabled
,
numberStatus
,
mobileStatus
:
numberStatus
,
mobile_status
:
numberStatus
,
linkedWecom
,
linked_wecom
:
linkedWecom
,
...
...
styles-v2.css
View file @
00d54727
...
...
@@ -1150,3 +1150,82 @@
align-items
:
center
;
gap
:
8px
;
}
/* Phone card filter toggle buttons and collapsible filter rows */
.phone-toolbar-main
{
flex-wrap
:
nowrap
;
}
.phone-toolbar-main
.toolbar-left
{
flex
:
0
0
auto
;
min-width
:
0
;
}
.phone-toolbar-actions
{
flex
:
1
1
auto
;
justify-content
:
flex-end
;
gap
:
8px
;
flex-wrap
:
nowrap
;
}
.filter-toggle-btn
{
flex
:
0
0
auto
;
height
:
32px
;
padding
:
0
14px
;
border
:
1px
solid
#e5e7eb
;
border-radius
:
6px
;
background
:
#fff
;
color
:
#4b5563
;
font-size
:
13px
;
font-weight
:
500
;
cursor
:
pointer
;
white-space
:
nowrap
;
transition
:
border-color
0.15s
ease
,
color
0.15s
ease
,
background
0.15s
ease
;
}
.filter-toggle-btn
:hover
{
border-color
:
#93c5fd
;
color
:
#2563eb
;
}
.filter-toggle-btn.is-active
{
background
:
#eff6ff
;
border-color
:
#3b82f6
;
color
:
#2563eb
;
font-weight
:
600
;
}
.phone-search-input
{
flex
:
0
0
220px
;
}
.phone-filter-row
{
display
:
flex
;
align-items
:
center
;
gap
:
8px
;
flex-wrap
:
wrap
;
padding
:
12px
20px
;
border-bottom
:
1px
solid
#f3f4f6
;
background
:
#fafbfc
;
}
.phone-filter-row
.el-select
,
.phone-filter-row
.el-date-editor
,
.phone-filter-row
.el-input
{
margin
:
0
;
}
.phone-date-range.el-date-editor.el-input__wrapper
,
.phone-date-range
{
width
:
190px
!important
;
flex
:
0
0
190px
;
}
.phone-date-range
.el-range-input
{
min-width
:
0
!important
;
width
:
68px
!important
;
}
.phone-date-range
.el-range-separator
{
padding
:
0
2px
!important
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment