123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393 |
- <template>
- <div class="h-full flex p-3 flex-col businessDetail" v-loading="allLoading.skeletonLoading">
- <div class="w-full bg-white p-2 mb-2 shadow-md rounded-md flex items-center">
- <div class="icon mr-4">
- <el-link :underline="false" @click="backPath()">
- <el-icon class="el-icon--right"><icon-view /></el-icon> 返回商机列表
- </el-link>
- </div>
- <div class="mr-8">
- <el-select v-model="optionVal" placeholder="请选择" style="width: 250px" filterable @change="selectChange()">
- <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
- </el-select>
- </div>
- <div class="flex-1 flex h-full justify-end overflow-auto scroll-bar-hide cursor-pointer" @wheel="handleScroll">
- <div
- :class="`${index === 0 ? 'startStep' : 'nextStep'} ${(currentStage >= index || businessInfo.stageValue == '赢单') ? 'selected' : (currentStage >= index || businessInfo.stageValue == '输单') ? 'backOrange' : 'backGray'} relative rounded-md flex items-center pl-6 pr-6`"
- v-for="(item, index) in stageList" :key="index">
- <div class="pr-3 text-nowrap">{{ item.name }}</div>
- <div class="text-nowrap">{{ item.plan }}</div>
- </div>
- </div>
- <div class="relative rounded-md flex items-center itemPing backGray endStep item pl-6 pr-6 mr-4 resetStyle"
- v-if="currentStage >= 0">
- <el-select v-model="stageStatusVal" placeholder="结束" style="width: 100px" class="selectClas"
- @change="advanceChange()">
- <el-option v-for="(item, index) in stageListOption" :key="index" :label="item.label" :value="item.value" />
- </el-select>
- </div>
- <div
- class="relative rounded-md flex items-center justify-around backOrange endStep item pl-6 pr-6 mr-4 resetStyle"
- v-if="businessInfo.stageValue == '输单'" style="padding-top: 6px;padding-bottom: 6px;">
- <div>{{ businessInfo.stageValue }}</div>
- <div class="ml-5">0%</div>
- </div>
- <div class="relative rounded-md flex items-center justify-around backWan endStep item pl-6 pr-6 mr-4 resetStyle"
- v-if="businessInfo.stageValue == '赢单'" style="padding-top: 6px;padding-bottom: 6px;">
- <div>{{ businessInfo.stageValue }}</div>
- <div class="ml-4"> 100%</div>
- </div>
- <div class="relative rounded-md flex items-center justify-around backGray endStep item pl-6 pr-6 mr-4 resetStyle"
- v-if="businessInfo.stageValue == '无效'" style="padding-top: 6px;padding-bottom: 6px;">
- <div>{{ businessInfo.stageValue }}</div>
- <div class="ml-5">0%</div>
- </div>
- <div class="bg-[#075985] rounded-md text itemPing pl-2 pr-2 flex items-center aloneText"
- v-if="currentStage != -1">
- <!-- <el-link :underline="false" v-if="(currentStage + 1) != stageList.length"
- @click="advancementStage(false)">推进至下个阶段【{{ stageList[currentStage +
- 1]?.name }}】</el-link> -->
- <el-link :underline="false" v-if="(currentStage + 1) != stageList.length"
- @click="advancementStageNext(false)">推进至下个阶段【{{ stageList[currentStage +
- 1]?.name }}】</el-link>
- <el-link :underline="false" v-else class="ml-4 mr-4" @click="advancementStage(true)">赢单</el-link>
- </div>
- </div>
- <!-- 内容 -->
- <div class="flex-1 flex flex-col overflow-y-auto overflow-x-hidden scroll-bar">
- <div class="w-full h-auto flex justify-between">
- <div class="bg-white shadow-md rounded-md" style="width: 46%;">
- <Information :information="businessInfo" @refreshData="refreshData" />
- </div>
- <div class="bg-white ml-2 shadow-md rounded-md flex-1">
- <Attachment :information="businessInfo" @refreshData="refreshData" />
- </div>
- </div>
- <div class="w-full h-auto flex justify-between mt-2">
- <div class="bg-white shadow-md rounded-md" style="width: 65%;">
- <DetailCompinents :data="detailCompinentsData" :information="businessInfo" :formTaskType="1"
- :filed="'businessOpportunityId'" :disabledList="['taskType', 'businessOpportunityId']"
- @refreshData="getDetail" />
- </div>
- <div class="bg-white ml-2 shadow-md rounded-md flex-1">
- <OperationRecord :information="businessInfo" />
- </div>
- </div>
- <div class="w-full h-auto flex justify-between mt-2">
- <div class="bg-white shadow-md rounded-md w-full">
- <Products :information="businessInfo" @refreshData="getDetail" />
- </div>
- </div>
- </div>
- <!-- 弹窗 -->
- <el-dialog v-model="allVisible.advanceVisible" width="800" :show-close="false" top="10vh">
- <template #header="{ close, titleId, titleClass }">
- <div class="flex justify-between items-center border-b pb-3 dialog-header">
- <h4 :id="titleId">{{ allText.advanceText }}原因</h4>
- <div>
- <el-button type="primary" :loading="allLoading.advanceSaveLoading" @click="advanceSave(true)">保存</el-button>
- <el-button @click="advanceClose">取消</el-button>
- </div>
- </div>
- </template>
- <div class="pt-3">
- <div>请输入{{ allText.advanceText }}原因</div>
- <el-input v-model.trim="advanceVal" style="width: 100%" class="pb-3" :placeholder="'请输入'" clearable />
- </div>
- </el-dialog>
- </div>
- </template>
- <script lang="ts" setup>
- import { ref, reactive, onMounted, inject } from "vue";
- import type { FormInstance, FormRules } from 'element-plus'
- import { Edit, ArrowLeft as IconView } from '@element-plus/icons-vue'
- import { backPath } from '@/utils/tools'
- import { useRoute } from "vue-router";
- import { BUSIESS_ALL, BUSIESS_GETSATE, BUSIESS_INFO, URL_SAVEREASON, URL_STAGEIDNEXT } from '../api'
- import Information from '../component/information.vue'
- import Attachment from '../component/attachment.vue'
- // import RelatedTasks from '../component/relatedTasks.vue';
- import DetailCompinents from '@/components/detailcompinents/relatedTasks.vue'
- import OperationRecord from '../component/operationRecord.vue';
- import Products from '../component/products.vue';
- import { post } from "@/utils/request";
- type stageListType = {
- name: string,
- plan: string,
- id?: number,
- }
- const route = useRoute()
- const globalPopup = inject<GlobalPopup>('globalPopup')
- const detailCompinentsData = ref([])
- const optionVal = ref<any>('')
- const stageStatusVal = ref<any>('')
- const stageStatusValOriginally = ref('')
- const advanceVal = ref('')
- const options = ref<optionType[]>([])
- const currentStage = ref<any>('') // 当前阶段的下标
- const allLoading = reactive({
- skeletonLoading: false,
- advanceSaveLoading: false
- })
- const allVisible = reactive({
- advanceVisible: false
- })
- const allText = reactive({
- advanceText: ''
- })
- const businessInfo = ref<any>({})
- const stageListOption = ref<optionType[]>([])
- const stageList = ref<stageListType[]>([])
- function refreshData() {
- getDetail()
- }
- function advancementStage(flag: boolean) {
- console.log('点击了推进阶段')
- if (!flag) {
- allLoading.advanceSaveLoading = true
- advancementStageNext(true)
- return
- }
- let val = stageListOption.value.find((item: any) => item.label == '赢单')
- stageStatusVal.value = Number(val?.value || '')
- advanceChange()
- }
- function advanceChange() {
- stageStatusValOriginally.value = JSON.parse(JSON.stringify(stageStatusVal.value))
- const item: any = stageListOption.value.find((item) => item.value === stageStatusVal.value)
- console.log(item)
- if (item.plan == '0%') {
- advanceVal.value = ''
- allText.advanceText = item.label
- allVisible.advanceVisible = true
- return
- }
- console.log(item, '<=====')
- allLoading.skeletonLoading = true
- post(URL_STAGEIDNEXT, {
- id: businessInfo.value.id,
- stageId: item.value,
- stageValue: item.label,
- }).then((_res) => {
- globalPopup?.showSuccess('操作成功')
- selectChange()
- }).finally(() => {
- setTimeout(() => {
- allLoading.skeletonLoading = false
- }, 500)
- })
- }
- function advanceClose() {
- stageStatusVal.value = stageStatusValOriginally.value
- allVisible.advanceVisible = false
- }
- function advanceSave(flag: boolean) {
- if (!advanceVal.value && flag) {
- globalPopup?.showError(`请输入${allText.advanceText}原因`)
- return
- }
- console.log(flag)
- if (flag) {
- allLoading.advanceSaveLoading = true
- advancementStageNext(true)
- return
- }
- }
- function loseOrder() {
- post(URL_SAVEREASON, {
- id: businessInfo.value.id,
- reason: advanceVal.value
- }).then((_res) => {
- globalPopup?.showSuccess('操作成功')
- selectChange()
- }).finally(() => {
- allLoading.advanceSaveLoading = false
- allVisible.advanceVisible = false
- })
- }
- function advancementStageNext(flag: boolean = false) {
- let fromVal = {}
- if (!flag) {
- fromVal = {
- id: businessInfo.value.id,
- stageId: stageList.value[currentStage.value + 1].id,
- stageValue: stageList.value[currentStage.value + 1].name,
- }
- } else {
- const item: any = stageListOption.value.find((item) => item.value === stageStatusVal.value)
- fromVal = {
- id: businessInfo.value.id,
- stageId: item.value,
- stageValue: item.label,
- }
- }
- post(URL_STAGEIDNEXT, { ...fromVal }).then((_res) => {
- if (!flag) {
- globalPopup?.showSuccess('操作成功')
- selectChange()
- } else {
- loseOrder()
- }
- }).catch(() => {
- allLoading.advanceSaveLoading = false
- allVisible.advanceVisible = false
- })
- }
- function getDetail() {
- allLoading.skeletonLoading = true
- post(BUSIESS_INFO, { id: optionVal.value }).then(({ data }) => {
- businessInfo.value = (data || []);
- detailCompinentsData.value = data.taskList || []
- setStageIndex()
- }).finally(() => {
- allLoading.skeletonLoading = false
- })
- }
- function handleScroll(event: any) { // 滚表横向滚动
- if (event.deltaY) {
- event.preventDefault();
- const element = event.currentTarget;
- element.scrollLeft += event.deltaY;
- }
- }
- function getOptionAll() {
- post(BUSIESS_ALL, {}).then((res) => {
- const { data } = res
- options.value = (data || []).map((item: any) => ({
- value: item.id + '',
- label: item.name
- }))
- })
- }
- function getSatge() {
- post(BUSIESS_GETSATE, {}).then(({ data }) => {
- stageList.value = (data || []).sort((a: any, b: any) => { return a.seq - b.seq; }).filter((item: any) => !item.isFinish).map((item: any) => ({ name: item.name, plan: item.plan, id: item.id }))
- stageListOption.value = (data || []).sort((a: any, b: any) => { return a.seq - b.seq; }).filter((item: any) => item.isFinish).map((item: any) => ({ label: item.name, value: item.id, plan: item.plan }))
- setStageIndex()
- })
- }
- function selectChange() {
- getDetail()
- }
- function setStageIndex() {
- currentStage.value = stageList.value.findIndex((item: any) => item.id == businessInfo.value.stageId)
- }
- onMounted(() => {
- const { id } = route.query
- optionVal.value = id
- getDetail()
- getOptionAll()
- getSatge()
- setTimeout(() => {
- setStageIndex()
- }, 500)
- })
- </script>
- <style lang="scss" scoped>
- .businessDetail {
- .selected {
- background-color: #075985 !important;
- color: #fff !important;
- }
- .icon {
- .el-link {
- color: #0052CC;
- }
- }
- .text {
- .el-link {
- color: #fff;
- font-size: 14px;
- }
- }
- .backDarkBlue {
- background-color: #0052CC;
- color: #fff;
- }
- .backGray {
- background-color: #F4F5F7;
- color: #606266;
- }
- .backOrange {
- background-color: #FF5531;
- color: #fff;
- }
- .backWan {
- background-color: #075985;
- color: #fff;
- }
- .startStep {
- clip-path: polygon(0% 0%,
- 90% 0%,
- 100% 50%,
- 90% 100%,
- 0% 100%);
- }
- .nextStep {
- clip-path: polygon(0% 0%,
- 90% 0%,
- 100% 50%,
- 90% 100%,
- 0% 100%,
- 10% 50%);
- }
- .endStep {
- clip-path: polygon(0% 0%,
- 100% 0%,
- 100% 100%,
- 0% 100%,
- 10% 50%);
- }
- .itemPing {
- padding-top: 4px;
- padding-bottom: 4px;
- }
- .aloneText {
- padding-top: 9px;
- padding-bottom: 9px;
- }
- }
- </style>
- <style lang="scss">
- .resetStyle {
- .el-select__wrapper {
- background-color: #F4F5F7;
- box-shadow: none !important;
- }
- }
- </style>
|