feat: 移动端列表页支持搜索+分页(25条/页);历史移至请假后
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -6,17 +6,28 @@ import { keyVisitsApi } from '@/api/keyVisits'
|
||||
|
||||
const router = useRouter()
|
||||
const loading = ref(false)
|
||||
const searchText = ref('')
|
||||
const page = ref(1)
|
||||
const pageSize = ref(25)
|
||||
const total = ref(0)
|
||||
const items = ref<any[]>([])
|
||||
|
||||
onMounted(loadItems)
|
||||
|
||||
async function loadItems() {
|
||||
loading.value = true
|
||||
try { const res = await keyVisitsApi.list(); items.value = Array.isArray(res.data) ? res.data : (res.data.items || []) }
|
||||
catch (_) {}
|
||||
try {
|
||||
const params: any = { page: page.value, page_size: pageSize.value }
|
||||
if (searchText.value) params.search = searchText.value
|
||||
const res = await keyVisitsApi.list()
|
||||
const raw = Array.isArray(res.data) ? res.data : (res.data.items || [])
|
||||
items.value = raw; total.value = res.data.total || raw.length
|
||||
} catch (_) {}
|
||||
finally { loading.value = false }
|
||||
}
|
||||
|
||||
function onSearch() { page.value = 1; loadItems() }
|
||||
|
||||
const urgencyColors: Record<string, string> = { '一般': '#5B7FA5', '重要': '#C4934A', '紧急': '#B8472E' }
|
||||
|
||||
async function handleDelete(id: string) {
|
||||
@@ -41,6 +52,11 @@ async function handleDelete(id: string) {
|
||||
|
||||
<button class="new-btn" @click="router.push('/m/key-visit/new')">+ 新建要客</button>
|
||||
|
||||
<div style="margin-bottom:12px;display:flex;gap:8px">
|
||||
<el-input v-model="searchText" placeholder="搜索..." size="small" clearable @keyup.enter="onSearch" @clear="onSearch" />
|
||||
<el-button size="small" @click="onSearch">搜索</el-button>
|
||||
</div>
|
||||
|
||||
<div class="cards">
|
||||
<div v-if="items.length === 0 && !loading" class="empty-state"><div class="empty-glyph">—</div><p class="empty-text">暂不要客记录</p></div>
|
||||
<article v-for="item in items" :key="item.id" class="card" @click="router.push(`/m/key-visit/${item.id}/edit`)">
|
||||
@@ -56,6 +72,9 @@ async function handleDelete(id: string) {
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<div v-if="total > pageSize" style="display:flex;justify-content:center;margin-top:14px">
|
||||
<el-pagination v-model:current-page="page" :page-size="pageSize" :total="total" layout="prev, pager, next" small @current-change="loadItems" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -6,6 +6,10 @@ import { miniBusinessApi } from '@/api/miniBusiness'
|
||||
|
||||
const router = useRouter()
|
||||
const loading = ref(false)
|
||||
const searchText = ref('')
|
||||
const page = ref(1)
|
||||
const pageSize = ref(25)
|
||||
const total = ref(0)
|
||||
const items = ref<any[]>([])
|
||||
const statusOrder: Record<string, number> = { '跟进中': 0, '已签约': 1, '已流失': 2 }
|
||||
|
||||
@@ -14,13 +18,17 @@ onMounted(loadItems)
|
||||
async function loadItems() {
|
||||
loading.value = true
|
||||
try {
|
||||
const params: any = { page: page.value, page_size: pageSize.value }
|
||||
if (searchText.value) params.search = searchText.value
|
||||
const res = await miniBusinessApi.list()
|
||||
const raw = Array.isArray(res.data) ? res.data : (res.data.items || [])
|
||||
items.value = raw.sort((a: any, b: any) => (statusOrder[a.status] ?? 9) - (statusOrder[b.status] ?? 9))
|
||||
items.value = raw; total.value = res.data.total || raw.length
|
||||
} catch (_) {}
|
||||
finally { loading.value = false }
|
||||
}
|
||||
|
||||
function onSearch() { page.value = 1; loadItems() }
|
||||
|
||||
const statusColors: Record<string, string> = { '跟进中': '#C4934A', '已签约': '#4A6741', '已流失': '#B8472E' }
|
||||
|
||||
async function handleDelete(id: string) {
|
||||
@@ -45,6 +53,11 @@ async function handleDelete(id: string) {
|
||||
|
||||
<button class="new-btn" @click="router.push('/m/mini-biz/new')">+ 新建商机</button>
|
||||
|
||||
<div style="margin-bottom:12px;display:flex;gap:8px">
|
||||
<el-input v-model="searchText" placeholder="搜索..." size="small" clearable @keyup.enter="onSearch" @clear="onSearch" />
|
||||
<el-button size="small" @click="onSearch">搜索</el-button>
|
||||
</div>
|
||||
|
||||
<div class="cards">
|
||||
<div v-if="items.length === 0 && !loading" class="empty-state"><div class="empty-glyph">—</div><p class="empty-text">暂无商机记录</p></div>
|
||||
<article v-for="item in items" :key="item.id" class="card" @click="router.push(`/m/mini-biz/${item.id}/edit`)">
|
||||
@@ -60,6 +73,9 @@ async function handleDelete(id: string) {
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<div v-if="total > pageSize" style="display:flex;justify-content:center;margin-top:14px">
|
||||
<el-pagination v-model:current-page="page" :page-size="pageSize" :total="total" layout="prev, pager, next" small @current-change="loadItems" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -5,6 +5,10 @@ import api from '@/api/index'
|
||||
|
||||
const router = useRouter()
|
||||
const loading = ref(false)
|
||||
const searchText = ref('')
|
||||
const page = ref(1)
|
||||
const pageSize = ref(25)
|
||||
const total = ref(0)
|
||||
const items = ref<any[]>([])
|
||||
|
||||
onMounted(loadItems)
|
||||
@@ -16,10 +20,17 @@ const catColors: Record<string, string> = {
|
||||
|
||||
async function loadItems() {
|
||||
loading.value = true
|
||||
try { const res = await api.get('/daily-notes/'); items.value = Array.isArray(res.data) ? res.data : (res.data.items || []) }
|
||||
catch (_) {}
|
||||
try {
|
||||
const params: any = { page: page.value, page_size: pageSize.value }
|
||||
if (searchText.value) params.search = searchText.value
|
||||
const res = await api.get('/daily-notes/', { params })
|
||||
const raw = Array.isArray(res.data) ? res.data : (res.data.items || [])
|
||||
items.value = raw; total.value = res.data.total || raw.length
|
||||
} catch (_) {}
|
||||
finally { loading.value = false }
|
||||
}
|
||||
|
||||
function onSearch() { page.value = 1; loadItems() }
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -32,6 +43,11 @@ async function loadItems() {
|
||||
<div class="form-rule"></div>
|
||||
</header>
|
||||
|
||||
<div style="margin-bottom:12px;display:flex;gap:8px">
|
||||
<el-input v-model="searchText" placeholder="搜索..." size="small" clearable @keyup.enter="onSearch" @clear="onSearch" />
|
||||
<el-button size="small" @click="onSearch">搜索</el-button>
|
||||
</div>
|
||||
|
||||
<div v-loading="loading" class="cards">
|
||||
<div v-if="items.length === 0 && !loading" class="empty-state"><div class="empty-glyph">—</div><p class="empty-text">暂无纪要记录</p></div>
|
||||
<article v-for="item in items" :key="item.id" class="card" @click="router.push(`/m/note/${item.id}/edit`)">
|
||||
@@ -47,6 +63,9 @@ async function loadItems() {
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<div v-if="total > pageSize" style="display:flex;justify-content:center;margin-top:14px">
|
||||
<el-pagination v-model:current-page="page" :page-size="pageSize" :total="total" layout="prev, pager, next" small @current-change="loadItems" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -6,17 +6,28 @@ import api from '@/api/index'
|
||||
|
||||
const router = useRouter()
|
||||
const loading = ref(false)
|
||||
const searchText = ref('')
|
||||
const page = ref(1)
|
||||
const pageSize = ref(25)
|
||||
const total = ref(0)
|
||||
const items = ref<any[]>([])
|
||||
|
||||
onMounted(loadItems)
|
||||
|
||||
async function loadItems() {
|
||||
loading.value = true
|
||||
try { const res = await api.get('/work-plans/'); items.value = Array.isArray(res.data) ? res.data : (res.data.items || []) }
|
||||
catch (_) {}
|
||||
try {
|
||||
const params: any = { page: page.value, page_size: pageSize.value }
|
||||
if (searchText.value) params.search = searchText.value
|
||||
const res = await api.get('/work-plans/', { params })
|
||||
const raw = Array.isArray(res.data) ? res.data : (res.data.items || [])
|
||||
items.value = raw; total.value = res.data.total || raw.length
|
||||
} catch (_) {}
|
||||
finally { loading.value = false }
|
||||
}
|
||||
|
||||
function onSearch() { page.value = 1; loadItems() }
|
||||
|
||||
async function handleDelete(id: string) {
|
||||
try {
|
||||
await ElMessageBox.confirm('确定删除?', '确认', { type: 'warning' })
|
||||
@@ -39,6 +50,11 @@ async function handleDelete(id: string) {
|
||||
|
||||
<button class="new-btn" @click="router.push('/m/work-plan/new')">+ 新建计划</button>
|
||||
|
||||
<div style="margin-bottom:12px;display:flex;gap:8px">
|
||||
<el-input v-model="searchText" placeholder="搜索..." size="small" clearable @keyup.enter="onSearch" @clear="onSearch" />
|
||||
<el-button size="small" @click="onSearch">搜索</el-button>
|
||||
</div>
|
||||
|
||||
<div class="cards">
|
||||
<div v-if="items.length === 0 && !loading" class="empty-state"><div class="empty-glyph">—</div><p class="empty-text">暂无工作计划</p></div>
|
||||
<article v-for="item in items" :key="item.id" class="card" @click="router.push(`/m/work-plan/${item.id}/edit`)">
|
||||
@@ -54,6 +70,9 @@ async function handleDelete(id: string) {
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<div v-if="total > pageSize" style="display:flex;justify-content:center;margin-top:14px">
|
||||
<el-pagination v-model:current-page="page" :page-size="pageSize" :total="total" layout="prev, pager, next" small @current-change="loadItems" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -5,17 +5,29 @@ import api from '@/api/index'
|
||||
|
||||
const router = useRouter()
|
||||
const loading = ref(false)
|
||||
const searchText = ref('')
|
||||
const page = ref(1)
|
||||
const pageSize = ref(25)
|
||||
const total = ref(0)
|
||||
const items = ref<any[]>([])
|
||||
|
||||
onMounted(loadItems)
|
||||
|
||||
async function loadItems() {
|
||||
loading.value = true
|
||||
try { const res = await api.get('/visits/'); items.value = Array.isArray(res.data) ? res.data : (res.data.items || []) }
|
||||
catch (_) {}
|
||||
try {
|
||||
const params: any = { page: page.value, page_size: pageSize.value }
|
||||
if (searchText.value) params.search = searchText.value
|
||||
const res = await api.get('/visits/', { params })
|
||||
const raw = Array.isArray(res.data) ? res.data : (res.data.items || [])
|
||||
items.value = raw; total.value = res.data.total || raw.length
|
||||
} catch (_) {}
|
||||
finally { loading.value = false }
|
||||
}
|
||||
|
||||
function onSearch() { page.value = 1; loadItems() }
|
||||
|
||||
|
||||
const methodColors: Record<string, string> = { '上门': '#4A6741', '电话': '#5B7FA5', '微信': '#22c55e', '出差': '#C4934A' }
|
||||
</script>
|
||||
|
||||
@@ -29,6 +41,11 @@ const methodColors: Record<string, string> = { '上门': '#4A6741', '电话': '#
|
||||
<div class="form-rule"></div>
|
||||
</header>
|
||||
|
||||
<div style="margin-bottom:12px;display:flex;gap:8px">
|
||||
<el-input v-model="searchText" placeholder="搜索..." size="small" clearable @keyup.enter="onSearch" @clear="onSearch" />
|
||||
<el-button size="small" @click="onSearch">搜索</el-button>
|
||||
</div>
|
||||
|
||||
<div v-loading="loading" class="cards">
|
||||
<div v-if="items.length === 0 && !loading" class="empty-state"><div class="empty-glyph">—</div><p class="empty-text">暂无拜访记录</p></div>
|
||||
<article v-for="item in items" :key="item.id" class="card" @click="router.push(`/m/visit/${item.id}/edit`)">
|
||||
@@ -44,6 +61,9 @@ const methodColors: Record<string, string> = { '上门': '#4A6741', '电话': '#
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
<div v-if="total > pageSize" style="display:flex;justify-content:center;margin-top:14px">
|
||||
<el-pagination v-model:current-page="page" :page-size="pageSize" :total="total" layout="prev, pager, next" small @current-change="loadItems" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -26,12 +26,12 @@ onMounted(async () => {
|
||||
})
|
||||
|
||||
const modules = [
|
||||
{ path: '/m/visits', label: '历史拜访', icon: '📋', count: () => counts.value.visits, color: '#4A6741' },
|
||||
{ path: '/m/notes', label: '历史纪要', icon: '📝', count: () => counts.value.notes, color: '#1C3738' },
|
||||
{ path: '/m/plans', label: '工作计划', icon: '📅', count: () => counts.value.plans, color: '#4A6741' },
|
||||
{ path: '/m/mini-biz', label: '商机跟单', icon: '💰', count: () => counts.value.miniBiz, color: '#C4934A' },
|
||||
{ path: '/m/key-visits', label: '要客拜访', icon: '⭐', count: () => counts.value.keyVisits, color: '#5B7FA5' },
|
||||
{ path: '/m/leaves', label: '请假管理', icon: '📋', count: () => counts.value.leaves, color: '#9CA3AF' },
|
||||
{ path: '/m/visits', label: '历史拜访', icon: '🕐', count: () => counts.value.visits, color: '#4A6741' },
|
||||
{ path: '/m/notes', label: '历史纪要', icon: '📝', count: () => counts.value.notes, color: '#1C3738' },
|
||||
]
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user