LatestProgress.vue 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. <template>
  2. <div v-loading="loading" class="progress">
  3. <el-timeline reverse>
  4. <el-timeline-item
  5. v-for="(item, index) in progressList"
  6. :key="index"
  7. color="#0084FF"
  8. placement="top"
  9. hide-timestamp
  10. >
  11. <div class="details" :style="getColor(item.type)">
  12. <div class="t">{{ getTitle(item.type) }}</div>
  13. <div class="content11" v-if="item.type != 30">
  14. <span class="gray">跟进摘要: </span>
  15. <span class="val">
  16. <!-- {{ getContent(item) }} -->
  17. <span v-if="item.type === 10">报价单总金额</span>
  18. <span v-if="item.type === 20">合同总金额</span>
  19. <span>{{ moneyFormat(item.amount, 2) }}</span>
  20. <span
  21. v-if="item.type === 10 && item.code"
  22. :class="{ 'code-class': isHave }"
  23. @click="isHaveOne ? handlePushRoute(item) : () => {}"
  24. >({{ item.code }})</span
  25. >
  26. <span
  27. v-if="item.type === 20 && item.contractCode"
  28. :class="{ 'code-class': isHaveOne }"
  29. @click="isHave ? handlePushRoute(item) : () => {}"
  30. >({{ item.contractCode }})</span
  31. >
  32. </span>
  33. </div>
  34. <div class="content11" v-else>
  35. <span class="gray">跟进记录: </span>
  36. <span class="val"> {{ item.remark }} </span>
  37. </div>
  38. <div
  39. style="margin: 8px 0; display: flex"
  40. v-if="item.fileList && item.fileList.length > 0"
  41. >
  42. <div style="width: 36px; color: #999999">附件:</div>
  43. <div style="width: calc(100% - 36px)">
  44. <div v-for="(file, index) in item.fileList" :key="index">
  45. <a
  46. style="color: #409eff; cursor: pointer"
  47. @click="openFile(file.fileUrl)"
  48. >{{ file.fileName }}</a
  49. >
  50. </div>
  51. </div>
  52. </div>
  53. <div class="gray">{{ item.createTime }}</div>
  54. </div>
  55. </el-timeline-item>
  56. </el-timeline>
  57. </div>
  58. </template>
  59. <script setup>
  60. import useUserStore from "@/store/modules/user";
  61. const props = defineProps({
  62. customerId: {
  63. type: String,
  64. },
  65. });
  66. const { proxy } = getCurrentInstance();
  67. const loading = ref(false);
  68. const progressList = ref([]);
  69. // 判断当前用户有无销售合同页面权限
  70. const isHave = ref(false);
  71. if (
  72. useUserStore().permissions &&
  73. useUserStore().permissions.includes("contract")
  74. ) {
  75. isHave.value = true;
  76. }
  77. // 判断当前用户有无报价单页面权限
  78. const isHaveOne = ref(false);
  79. if (
  80. useUserStore().permissions &&
  81. useUserStore().permissions.includes("priceSheet")
  82. ) {
  83. isHaveOne.value = true;
  84. }
  85. const getData = () => {
  86. loading.value = true;
  87. proxy
  88. .post("/saleQuotation/latestFollowUp", { id: props.customerId })
  89. .then((res) => {
  90. progressList.value = res.rows;
  91. if (
  92. res.rows &&
  93. res.rows.length > 0 &&
  94. res.rows.map((rows) => rows.id).length > 0
  95. ) {
  96. proxy
  97. .post("/fileInfo/getList", {
  98. businessIdList: res.rows.map((rows) => rows.id),
  99. })
  100. .then((fileObj) => {
  101. for (let i = 0; i < res.rows.length; i++) {
  102. progressList.value[i].fileList =
  103. fileObj[progressList.value[i].id] || [];
  104. }
  105. });
  106. }
  107. setTimeout(() => {
  108. loading.value = false;
  109. }, 200);
  110. });
  111. };
  112. onMounted(() => {
  113. if (props.customerId) {
  114. getData();
  115. }
  116. });
  117. const getTitle = (type) => {
  118. switch (type) {
  119. case 10:
  120. return "报价单";
  121. case 20:
  122. return "合同";
  123. case 30:
  124. return "手动跟进";
  125. default:
  126. return "";
  127. }
  128. };
  129. const getContent = (item) => {
  130. if (item.type === 10) {
  131. return "报价单总金额 " + proxy.moneyFormat(item.amount, 2);
  132. } else if (item.type === 20) {
  133. return (
  134. "合同总金额 " +
  135. proxy.moneyFormat(item.amount, 2) +
  136. ` (${item.contractCode}) `
  137. );
  138. }
  139. };
  140. const openFile = (path) => {
  141. window.open(path, "_blank");
  142. };
  143. const getColor = (type) => {
  144. const obj = {
  145. 0: "#EAE8FB",
  146. 10: "#FCF1E4",
  147. 20: "#E2FBE8",
  148. 30: "#D9EDFF",
  149. 40: "#E4F9F9",
  150. };
  151. return "background-color: " + obj[type];
  152. };
  153. const handlePushRoute = (row) => {
  154. if (row.type === 10) {
  155. proxy.$router.push({
  156. name: "PriceSheet",
  157. query: {
  158. code: row.code,
  159. },
  160. });
  161. } else if (row.type === 20) {
  162. proxy.$router.push({
  163. name: "Contract",
  164. query: {
  165. code: row.contractCode,
  166. },
  167. });
  168. }
  169. };
  170. </script>
  171. <style lang="scss" scoped>
  172. .code-class {
  173. cursor: pointer;
  174. color: #409eff;
  175. }
  176. :deep(.el-timeline-item) {
  177. padding-bottom: 10px;
  178. }
  179. :deep(.el-timeline-item__wrapper) {
  180. top: 5px;
  181. }
  182. .progress {
  183. padding: 10px;
  184. }
  185. .details {
  186. padding: 10px;
  187. // background-color: #d9edff;
  188. border-radius: 5px;
  189. font-size: 12px;
  190. .t {
  191. color: #333333;
  192. font-weight: bold;
  193. }
  194. .content11 {
  195. margin: 4px 0;
  196. display: flex;
  197. .val {
  198. flex: 1;
  199. overflow: hidden;
  200. white-space: nowrap;
  201. text-overflow: ellipsis;
  202. }
  203. }
  204. .gray {
  205. color: #999999;
  206. }
  207. }
  208. </style>
  209. <style>
  210. ul {
  211. margin: 0px;
  212. padding: 0px;
  213. }
  214. </style>