index.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. <template>
  2. <div class="app-container">
  3. <!-- 搜索区域 -->
  4. <el-card shadow="never" class="search-card">
  5. <el-form :model="queryParams" ref="queryRef" inline label-width="80px">
  6. <el-form-item label="拜访人" prop="callPeopleName" class="custom-form-item">
  7. <el-input v-model="queryParams.callPeopleName" placeholder="请输入拜访人" clearable />
  8. </el-form-item>
  9. <el-form-item label="拜访日期" prop="callDate" class="custom-form-item">
  10. <el-date-picker v-model="queryParams.callDate" type="date" placeholder="请选择" value-format="YYYY-MM-DD" />
  11. </el-form-item>
  12. <el-form-item label="日程状态" prop="scheduleStatus" class="custom-form-item">
  13. <el-select v-model="queryParams.scheduleStatus" placeholder="请选择" clearable>
  14. <el-option
  15. v-for="dict in scheduleStatusOptions"
  16. :key="dict.value"
  17. :label="dict.label"
  18. :value="dict.value"
  19. />
  20. </el-select>
  21. </el-form-item>
  22. <div class="search-btns-area">
  23. <el-button icon="Search" @click="handleQuery">搜索</el-button>
  24. <el-button icon="Refresh" @click="resetQuery">重置</el-button>
  25. <el-button type="primary" icon="Plus" @click="handleAdd" v-hasPermi="['visit:routine:add']">新增</el-button>
  26. </div>
  27. </el-form>
  28. </el-card>
  29. <div class="title-container">
  30. <span class="list-title">拜访日程信息列表</span>
  31. </div>
  32. <!-- 列表区域 -->
  33. <el-card shadow="never" class="table-card">
  34. <el-table v-loading="loading" :data="dataList" border class="custom-table" :header-cell-style="{ background: '#f8fafc', color: '#333' }">
  35. <el-table-column label="日程编号" align="center" prop="scheduleNo" width="160">
  36. <template #default="scope">
  37. <span class="link-text" @click="handleDetail(scope.row)">{{ scope.row.scheduleNo }}</span>
  38. </template>
  39. </el-table-column>
  40. <el-table-column label="关联计划" align="center" prop="planNo" width="160" />
  41. <el-table-column label="客户名称" align="center" prop="customerName" min-width="200" show-overflow-tooltip />
  42. <el-table-column label="拜访人" align="center" prop="callPeopleName" width="100">
  43. <template #default="scope">
  44. <span>{{ staffOptions.find(s => String(s.staffId) === String(scope.row.callPeopleNo || scope.row.callPeopleName))?.staffName || scope.row.callPeopleName || '' }}</span>
  45. </template>
  46. </el-table-column>
  47. <el-table-column label="拜访日期" align="center" prop="callDate" width="120" >
  48. <template #default="scope">
  49. <span>{{ parseTime(scope.row.callDate, '{y}-{m}-{d}') }}</span>
  50. </template>
  51. </el-table-column>
  52. <el-table-column label="随访人" align="center" prop="followPeopleName" width="120" />
  53. <el-table-column label="关联对象" align="center" prop="objectName" width="180" show-overflow-tooltip>
  54. <template #default="scope">
  55. <span>{{ scope.row.objectName || scope.row.customerName || '' }}</span>
  56. </template>
  57. </el-table-column>
  58. <el-table-column label="状态" align="center" prop="scheduleStatus" width="100">
  59. <template #default="scope">
  60. <el-tag :type="String(scope.row.scheduleStatus) === '0' ? 'warning' : (String(scope.row.scheduleStatus) === '1' ? 'success' : 'danger')">
  61. {{ scheduleStatusOptions.find(d => String(d.value) === String(scope.row.scheduleStatus))?.label || (String(scope.row.scheduleStatus) === '0' ? '未执行' : (String(scope.row.scheduleStatus) === '1' ? '已执行' : '放弃执行')) }}
  62. </el-tag>
  63. </template>
  64. </el-table-column>
  65. <el-table-column label="关联类型" align="center" prop="relevanceType" width="100">
  66. <template #default="scope">
  67. {{ relevanceOptions.find(d => String(d.value) === String(scope.row.relevanceType))?.label || (String(scope.row.relevanceType) === '0' ? '客户' : (String(scope.row.relevanceType) === '1' ? '项目' : '供应商')) }}
  68. </template>
  69. </el-table-column>
  70. <el-table-column label="重要级别" align="center" prop="importantLevel" width="100">
  71. <template #default="scope">
  72. <span>{{ importanceOptions.find(d => String(d.value) === String(scope.row.importantLevel))?.label || scope.row.importantLevel || '' }}</span>
  73. </template>
  74. </el-table-column>
  75. <el-table-column label="操作" align="center" width="180" fixed="right">
  76. <template #default="scope">
  77. <el-button link type="primary" @click="handleDetail(scope.row)">详情</el-button>
  78. <el-button link type="primary" @click="handleUpdate(scope.row)" v-hasPermi="['visit:routine:edit']">编辑</el-button>
  79. <el-button link type="danger" @click="handleDelete(scope.row)" v-hasPermi="['visit:routine:remove']">删除</el-button>
  80. </template>
  81. </el-table-column>
  82. </el-table>
  83. <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
  84. </el-card>
  85. <!-- 新增组件 -->
  86. <AddRoutine v-model="addOpen" @success="getList" />
  87. <!-- 编辑组件 -->
  88. <EditRoutine v-model="editOpen" :id="activeId" @success="getList" />
  89. <!-- 详情组件 -->
  90. <DetailRoutine v-model="detailOpen" :id="activeId" />
  91. </div>
  92. </template>
  93. <script setup name="VisitRoutine">
  94. import { ref, reactive, onMounted, getCurrentInstance, toRefs } from 'vue';
  95. import { listRoutine, delRoutine } from "@/api/visit/routine";
  96. import { selectStaffOptionList } from "@/api/customer/crmStaff";
  97. import AddRoutine from './add.vue';
  98. import EditRoutine from './edit.vue';
  99. import DetailRoutine from './detail.vue';
  100. const proxy = getCurrentInstance().proxy;
  101. const {
  102. importance_level: importanceOptions,
  103. schedule_status: scheduleStatusOptions,
  104. relevance_type: relevanceOptions
  105. } = toRefs(reactive(proxy.useDict("importance_level", "schedule_status", "relevance_type")));
  106. const staffOptions = ref([]);
  107. const queryRef = ref(null);
  108. const loading = ref(false);
  109. const dataList = ref([]);
  110. const total = ref(0);
  111. const queryParams = reactive({
  112. pageNum: 1,
  113. pageSize: 10,
  114. callPeopleName: undefined,
  115. callDate: undefined,
  116. scheduleStatus: undefined,
  117. orderByColumn: 'createTime',
  118. isAsc: 'desc'
  119. });
  120. const addOpen = ref(false);
  121. const editOpen = ref(false);
  122. const detailOpen = ref(false);
  123. const activeId = ref(null);
  124. const getList = () => {
  125. loading.value = true;
  126. listRoutine(queryParams).then(response => {
  127. dataList.value = response.rows || [];
  128. total.value = response.total || 0;
  129. loading.value = false;
  130. }).catch(() => {
  131. loading.value = false;
  132. });
  133. };
  134. const handleQuery = () => {
  135. queryParams.pageNum = 1;
  136. getList();
  137. };
  138. const resetQuery = () => {
  139. if (queryRef.value) {
  140. queryRef.value.resetFields();
  141. }
  142. handleQuery();
  143. };
  144. const handleAdd = () => {
  145. addOpen.value = true;
  146. };
  147. const handleUpdate = (row) => {
  148. activeId.value = row.id;
  149. editOpen.value = true;
  150. };
  151. const handleDetail = (row) => {
  152. activeId.value = row.id;
  153. detailOpen.value = true;
  154. };
  155. const handleDelete = (row) => {
  156. const ids = row.id;
  157. const scheduleNo = row.scheduleNo || ids;
  158. proxy.$modal.confirm(`确认删除日程编号为"${scheduleNo}"的数据项吗?`).then(() => {
  159. return delRoutine(ids);
  160. }).then(() => {
  161. getList();
  162. proxy.$modal.msgSuccess("删除成功");
  163. }).catch(() => {});
  164. };
  165. const getOptions = () => {
  166. selectStaffOptionList().then(res => { staffOptions.value = res.data || []; });
  167. };
  168. onMounted(() => {
  169. getList();
  170. getOptions();
  171. });
  172. </script>
  173. <style scoped lang="scss">
  174. .app-container {
  175. padding: 20px;
  176. background-color: #f5f7fa;
  177. min-height: calc(100vh - 84px);
  178. }
  179. .search-card {
  180. border: none;
  181. margin-bottom: 20px;
  182. :deep(.el-card__body) {
  183. padding: 15px 20px;
  184. }
  185. }
  186. :deep(.el-form--inline) {
  187. display: flex;
  188. align-items: center;
  189. }
  190. .custom-form-item {
  191. margin-bottom: 0 !important;
  192. margin-right: 0px;
  193. :deep(.el-form-item__label) {
  194. padding-right: 12px;
  195. color: #606266;
  196. font-weight: normal;
  197. }
  198. :deep(.el-input), :deep(.el-select), :deep(.el-date-editor) {
  199. width: 220px;
  200. }
  201. }
  202. .search-btns-area {
  203. margin-left: auto;
  204. display: flex;
  205. align-items: center;
  206. gap: 12px;
  207. }
  208. .title-container {
  209. padding: 15px 20px;
  210. background-color: #fff;
  211. border-bottom: 1px solid #ebeef5;
  212. border-radius: 4px 4px 0 0;
  213. .list-title { font-size: 15px; color: #333; font-weight: normal; }
  214. }
  215. .table-card {
  216. border: none;
  217. border-radius: 0 0 4px 4px;
  218. :deep(.el-card__body) { padding: 10px 20px 20px; }
  219. }
  220. :deep(.el-table__header th .cell) {
  221. font-weight: normal;
  222. }
  223. :deep(.el-button--primary.is-link) {
  224. color: #409eff;
  225. }
  226. :deep(.el-button--danger.is-link) {
  227. color: #f56c6c;
  228. }
  229. .link-text { color: #409eff; cursor: pointer; }
  230. </style>