Files
shanxia2.0/miniprogram/pages/crm/opportunity/detail.vue
T
2026-07-18 09:14:02 +08:00

135 lines
4.9 KiB
Vue

<script setup>
import { ref } from 'vue'
import { onLoad, onShow } from '@dcloudio/uni-app'
import { getOpportunity, listOpportunityFollow, addOpportunityFollow } from '@/api/crm'
import { labelOf, dash, formatMoney } from '@/utils/crmLabels'
import { PAGE_PATHS } from '@/config/api'
const id = ref('')
const detail = ref(null)
const follows = ref([])
const showFollow = ref(false)
const followContent = ref('')
const followType = ref('电话')
const submitting = ref(false)
const stageLabel = (s) => labelOf('opportunityStage', s)
const statusLabel = (s) => labelOf('opportunityStatus', s)
const goBack = () => {
uni.navigateBack({
fail: () => uni.navigateTo({ url: PAGE_PATHS.crmOpportunityList })
})
}
const load = async () => {
if (!id.value) return
try {
detail.value = await getOpportunity(id.value)
const fl = await listOpportunityFollow(id.value, 1, 50)
follows.value = fl.rows || []
} catch (e) {
uni.showToast({ title: e.message || '加载失败', icon: 'none' })
}
}
const submitFollow = async () => {
if (!followContent.value.trim()) {
uni.showToast({ title: '请填写跟进内容', icon: 'none' })
return
}
submitting.value = true
try {
await addOpportunityFollow({
opportunityId: id.value,
followType: followType.value,
followContent: followContent.value.trim()
})
uni.showToast({ title: '已保存', icon: 'success' })
showFollow.value = false
followContent.value = ''
await load()
} catch (e) {
uni.showToast({ title: e.message || '保存失败', icon: 'none' })
} finally {
submitting.value = false
}
}
onLoad((q) => {
id.value = q?.id || ''
})
onShow(() => load())
</script>
<template>
<view class="mp-page mp-page--sub mp-page--with-bottom">
<view class="mp-header">
<text class="mp-subpage-back" @click="goBack">← 返回</text>
<text class="mp-header__title" style="margin-top: 16rpx">商机详情</text>
</view>
<view v-if="detail" class="mp-detail-hero">
<view class="mp-detail-hero__top">
<view>
<text class="mp-detail-hero__title">{{ dash(detail.opportunityName) }}</text>
<text class="mp-detail-hero__sub">{{ dash(detail.customerName) }}</text>
</view>
<text class="mp-tag" :class="'mp-tag--' + statusLabel(detail.status).tag">
{{ statusLabel(detail.status).text }}
</text>
</view>
<view class="mp-detail-hero__meta">
<text class="mp-detail-hero__chip">{{ stageLabel(detail.stage).text }}</text>
<text class="mp-detail-hero__chip">{{ formatMoney(detail.amount ?? detail.expectedAmount) }}</text>
</view>
</view>
<view class="mp-block">
<text class="mp-block__title">基本信息</text>
<view class="mp-block__panel">
<view class="mp-kv"><text class="mp-kv__label">商机编号</text><text class="mp-kv__value">{{ dash(detail?.opportunityNo) }}</text></view>
<view class="mp-kv"><text class="mp-kv__label">负责人</text><text class="mp-kv__value">{{ dash(detail?.ownerUserName) }}</text></view>
<view class="mp-kv"><text class="mp-kv__label">来源</text><text class="mp-kv__value">{{ dash(detail?.source) }}</text></view>
<view class="mp-kv"><text class="mp-kv__label">预计成交</text><text class="mp-kv__value">{{ dash(detail?.expectedDate || detail?.dealDate) }}</text></view>
<view class="mp-kv"><text class="mp-kv__label">备注</text><text class="mp-kv__value">{{ dash(detail?.remark) }}</text></view>
</view>
</view>
<view class="mp-block">
<text class="mp-block__title">跟进记录</text>
<mp-empty v-if="!follows.length" compact title="暂无跟进" />
<view v-else class="mp-list">
<view v-for="f in follows" :key="f.id" class="mp-card">
<view class="mp-card__head">
<text class="mp-card__title">{{ dash(f.followType) }}</text>
<text class="mp-card__sub">{{ dash(f.createTime) }}</text>
</view>
<text style="font-size: 26rpx">{{ dash(f.followContent) }}</text>
</view>
</view>
</view>
<view v-if="showFollow" class="mp-form-panel">
<view class="mp-form-row">
<text class="mp-form-label">跟进方式</text>
<input v-model="followType" class="mp-form-input" />
</view>
<view class="mp-form-row">
<text class="mp-form-label mp-form-label--req">跟进内容</text>
<textarea v-model="followContent" class="mp-form-textarea" />
</view>
<view class="mp-form-row" style="display: flex; gap: 16rpx">
<view class="mp-btn mp-btn--ghost" style="flex: 1" @click="showFollow = false">取消</view>
<view class="mp-btn mp-btn--primary" style="flex: 1" @click="submitFollow">
{{ submitting ? '提交中…' : '提交' }}
</view>
</view>
</view>
<view class="mp-bottom-bar">
<view class="mp-btn mp-btn--primary" @click="showFollow = true">写跟进</view>
</view>
</view>
</template>