feat: 支局长/分管领导可为任意客户经理代填记录
后端: - 5个模块的 Create/Update schema 新增可选 manager_id 字段 - POST 端点: director/leader 可指定 manager_id,manager 角色自动用自身 - PUT 端点: director/leader 可修改 manager_id,manager 角色禁止修改 前端(移动端+桌面端共10个页面): - 支局长/领导可见「客户经理」下拉选择框 - 创建和编辑时均可指定记录归属的客户经理 - 涵盖今日拜访、今日纪要、工作计划、商机跟单、要客拜访五个模块 Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -3,13 +3,16 @@ import { ref, onMounted, computed } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||
import { todayStr } from '@/utils'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import api from '@/api/index'
|
||||
import EditLogPanel from '@/components/EditLogPanel.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const auth = useAuthStore()
|
||||
const isEdit = computed(() => !!route.params.id)
|
||||
const submitLoading = ref(false)
|
||||
const allManagers = ref<any[]>([])
|
||||
|
||||
const categories = ['行政事务', '合同整理', '发票处理', '内部会议', '培训学习', '其他']
|
||||
|
||||
@@ -24,6 +27,7 @@ const form = ref({
|
||||
category: '其他',
|
||||
content: '',
|
||||
time_range: '',
|
||||
manager_id: auth.userId || '',
|
||||
})
|
||||
|
||||
function onTimeRangeChange(val: [string, string] | null) {
|
||||
@@ -36,6 +40,9 @@ function parseTimeRange(str: string): [string, string] | null {
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (auth.isDirector || auth.isLeader) {
|
||||
try { const res = await api.get('/users/', { params: { role: 'manager' } }); allManagers.value = res.data } catch (_) {}
|
||||
}
|
||||
if (isEdit.value) {
|
||||
try {
|
||||
const res = await api.get(`/daily-notes/${route.params.id}`)
|
||||
@@ -45,6 +52,7 @@ onMounted(async () => {
|
||||
category: n.category,
|
||||
content: n.content || '',
|
||||
time_range: n.time_range || '',
|
||||
manager_id: n.manager_id || auth.userId || '',
|
||||
}
|
||||
timeRangeValue.value = parseTimeRange(n.time_range)
|
||||
} catch (_) {}
|
||||
@@ -105,6 +113,13 @@ async function handleDelete() {
|
||||
<el-date-picker v-model="form.note_date" type="date" style="width:100%" />
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="auth.isDirector || auth.isLeader">
|
||||
<template #label><span class="form-label">客户经理</span></template>
|
||||
<el-select v-model="form.manager_id" filterable placeholder="选择客户经理" style="width:100%">
|
||||
<el-option v-for="m in allManagers" :key="m.id" :label="m.name" :value="m.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span class="form-label">分类</span>
|
||||
|
||||
@@ -4,12 +4,15 @@ import { useRouter } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { keyVisitsApi } from '@/api/keyVisits'
|
||||
import { customersApi } from '@/api/customers'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import api from '@/api/index'
|
||||
|
||||
const router = useRouter()
|
||||
const auth = useAuthStore()
|
||||
const submitLoading = ref(false)
|
||||
const customers = ref<any[]>([])
|
||||
const allUsers = ref<any[]>([])
|
||||
const allManagers = ref<any[]>([])
|
||||
|
||||
const urgencyLevels = ['一般', '重要', '紧急']
|
||||
const urgencyColors: Record<string, string> = {
|
||||
@@ -25,6 +28,7 @@ const form = ref({
|
||||
planned_date: '',
|
||||
planned_visitor: '',
|
||||
visit_target: '',
|
||||
manager_id: auth.userId || '',
|
||||
})
|
||||
|
||||
function onVisitorsChange(val: string[]) {
|
||||
@@ -33,6 +37,9 @@ function onVisitorsChange(val: string[]) {
|
||||
|
||||
onMounted(async () => {
|
||||
await Promise.all([loadCustomers(), loadUsers()])
|
||||
if (auth.isDirector || auth.isLeader) {
|
||||
api.get('/users/', { params: { role: 'manager' } }).then(r => { allManagers.value = r.data }).catch(() => {})
|
||||
}
|
||||
})
|
||||
|
||||
async function loadCustomers(q?: string) {
|
||||
@@ -88,6 +95,13 @@ async function handleSubmit() {
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="auth.isDirector || auth.isLeader">
|
||||
<template #label><span class="form-label">客户经理</span></template>
|
||||
<el-select v-model="form.manager_id" filterable placeholder="选择客户经理" style="width:100%">
|
||||
<el-option v-for="m in allManagers" :key="m.id" :label="m.name" :value="m.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<template #label><span class="form-label">紧急重要度</span></template>
|
||||
<div class="urgency-grid">
|
||||
|
||||
@@ -4,10 +4,14 @@ import { useRouter } from 'vue-router'
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { miniBusinessApi } from '@/api/miniBusiness'
|
||||
import { customersApi } from '@/api/customers'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import api from '@/api/index'
|
||||
|
||||
const router = useRouter()
|
||||
const auth = useAuthStore()
|
||||
const submitLoading = ref(false)
|
||||
const customers = ref<any[]>([])
|
||||
const allManagers = ref<any[]>([])
|
||||
|
||||
const form = ref({
|
||||
customer_id: '',
|
||||
@@ -16,9 +20,15 @@ const form = ref({
|
||||
follow_up_detail: '',
|
||||
status: '跟进中',
|
||||
expected_revenue_date: '',
|
||||
manager_id: auth.userId || '',
|
||||
})
|
||||
|
||||
onMounted(() => { loadCustomers() })
|
||||
onMounted(() => {
|
||||
loadCustomers()
|
||||
if (auth.isDirector || auth.isLeader) {
|
||||
api.get('/users/', { params: { role: 'manager' } }).then(r => { allManagers.value = r.data }).catch(() => {})
|
||||
}
|
||||
})
|
||||
|
||||
async function loadCustomers(q?: string) {
|
||||
try {
|
||||
@@ -66,6 +76,13 @@ async function handleSubmit() {
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="auth.isDirector || auth.isLeader">
|
||||
<template #label><span class="form-label">客户经理</span></template>
|
||||
<el-select v-model="form.manager_id" filterable placeholder="选择客户经理" style="width:100%">
|
||||
<el-option v-for="m in allManagers" :key="m.id" :label="m.name" :value="m.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<template #label><span class="form-label">产品类型</span></template>
|
||||
<el-input v-model="form.product_type" placeholder="例如: 云桌面、专线..." />
|
||||
|
||||
@@ -30,6 +30,7 @@ const form = ref({
|
||||
customer_demand: '',
|
||||
companions: [] as string[],
|
||||
photos: [] as string[],
|
||||
manager_id: auth.userId || '',
|
||||
})
|
||||
|
||||
const timeRangeValue = ref<any>(null)
|
||||
@@ -67,6 +68,7 @@ onMounted(async () => {
|
||||
customer_demand: v.customer_demand || '',
|
||||
companions: (v.companions || []).map(String),
|
||||
photos: v.photos || [],
|
||||
manager_id: v.manager_id || auth.userId || '',
|
||||
}
|
||||
uploadedPhotos.value = v.photos || []
|
||||
// Parse time range back into picker
|
||||
@@ -250,6 +252,13 @@ async function handleDelete() {
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="auth.isDirector || auth.isLeader">
|
||||
<template #label><span class="form-label">客户经理</span></template>
|
||||
<el-select v-model="form.manager_id" filterable placeholder="选择客户经理" style="width:100%">
|
||||
<el-option v-for="m in managers" :key="m.id" :label="m.name" :value="m.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<template #label>
|
||||
<span class="form-label">拜访日期</span>
|
||||
|
||||
@@ -5,19 +5,29 @@ import { ElMessage } from 'element-plus'
|
||||
import { todayStr } from '@/utils'
|
||||
import { workPlansApi } from '@/api/workPlans'
|
||||
import { customersApi } from '@/api/customers'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import api from '@/api/index'
|
||||
|
||||
const router = useRouter()
|
||||
const auth = useAuthStore()
|
||||
const submitLoading = ref(false)
|
||||
const customers = ref<any[]>([])
|
||||
const allManagers = ref<any[]>([])
|
||||
|
||||
const form = ref({
|
||||
customer_id: '',
|
||||
plan_content: '',
|
||||
plan_date: todayStr(),
|
||||
status: '计划中',
|
||||
manager_id: auth.userId || '',
|
||||
})
|
||||
|
||||
onMounted(() => { loadCustomers() })
|
||||
onMounted(() => {
|
||||
loadCustomers()
|
||||
if (auth.isDirector || auth.isLeader) {
|
||||
api.get('/users/', { params: { role: 'manager' } }).then(r => { allManagers.value = r.data }).catch(() => {})
|
||||
}
|
||||
})
|
||||
|
||||
async function loadCustomers(q?: string) {
|
||||
try {
|
||||
@@ -65,6 +75,13 @@ async function handleSubmit() {
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item v-if="auth.isDirector || auth.isLeader">
|
||||
<template #label><span class="form-label">客户经理</span></template>
|
||||
<el-select v-model="form.manager_id" filterable placeholder="选择客户经理" style="width:100%">
|
||||
<el-option v-for="m in allManagers" :key="m.id" :label="m.name" :value="m.id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-form-item>
|
||||
<template #label><span class="form-label">工作计划</span></template>
|
||||
<el-input v-model="form.plan_content" type="textarea" :rows="4" placeholder="描述下周工作计划..." />
|
||||
|
||||
Reference in New Issue
Block a user