index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. <template>
  2. <div class="oa-sys-list-view">
  3. <div class="searchBox">
  4. <div class="form">
  5. <span class="formSpan">项目名称:</span>
  6. <el-input v-model="queryParams.xmmc" placeholder="请输入项目名称" style="width: 210px" />
  7. </div>
  8. <div class="form">
  9. <span class="formSpan">项目部门:</span>
  10. <DeptTree v-model="queryParams['xmbmId']" placeholder="请选择部门" />
  11. </div>
  12. <div class="form">
  13. <span class="formSpan">跟踪人员:</span>
  14. <UserOrgTree v-model="queryParams['gzryId']" placeholder="请选择项目经理" />
  15. </div>
  16. <div class="from">
  17. <div class="btnBox">
  18. <el-button type="primary" style="background: #3485ff" @click="searchHandle">
  19. <img src="@/assets/imgs/OA/search.png" class="mr-8px" alt="" />
  20. 查询</el-button
  21. >
  22. <el-button type="primary" @click="addOrEditHandle()">
  23. <img src="@/assets/imgs/OA/open.png" class="mr-8px" alt="" />
  24. 新增</el-button
  25. >
  26. </div>
  27. </div>
  28. </div>
  29. <div class="infoBox">
  30. <ul>
  31. <li v-for="(item, index) in infoList" :key="index" class="mr-40px">
  32. <img class="mr-8px" :src="getAssetURL(item.icon)" alt="" />
  33. <p>{{ item.name }}:</p>
  34. <h4 class="font-size-18px" v-money:unit="item.num"></h4>
  35. </li>
  36. </ul>
  37. </div>
  38. <div class="tableBox">
  39. <div class="table" ref="tableRef">
  40. <el-table
  41. stripe
  42. :data="tableData"
  43. style="width: 100%; height: 100%"
  44. :style="{ height: tableHeight + 'px' }"
  45. :header-cell-style="{
  46. background: '#E5F0FB',
  47. color: '#233755',
  48. height: '50px'
  49. }"
  50. >
  51. <el-table-column label="序号" width="80">
  52. <template #default="scope">{{ scope.$index + 1 }}</template>
  53. </el-table-column>
  54. <el-table-column
  55. :show-overflow-tooltip="true"
  56. prop="xmmc"
  57. label="项目名称"
  58. :min-width="220"
  59. />
  60. <el-table-column prop="gzry" label="跟踪人员" width="140" />
  61. <el-table-column
  62. prop="ygje"
  63. label="预估金额(万元)"
  64. :show-overflow-tooltip="true"
  65. width="200"
  66. />
  67. <el-table-column prop="jf" label="甲方" width="120" />
  68. <el-table-column prop="jfdjr" label="甲方对接人" width="120" />
  69. <el-table-column prop="xmbm" label="项目归属部门" width="120" />
  70. <el-table-column prop="xzqdm" label="行政区" width="120" />
  71. <el-table-column prop="zt" label="状态" width="120">
  72. <template #default="scope">
  73. {{ ztMap[scope.row.zt] }}
  74. </template>
  75. </el-table-column>
  76. <el-table-column prop="xmjl" label="开关" width="120">
  77. <template #default="scope">
  78. <el-switch
  79. v-model="scope.row.status"
  80. :active-value="0"
  81. @change="switchChange(scope.row)"
  82. :inactive-value="1"
  83. />
  84. </template>
  85. </el-table-column>
  86. <el-table-column label="操作" width="80" fixed="right">
  87. <template #default="scope">
  88. <div
  89. class="operateBtn"
  90. @click="addOrEditHandle(scope.row)"
  91. v-if="scope.row.gzryId === user.user.id"
  92. >
  93. <span>编辑</span>
  94. </div>
  95. </template>
  96. </el-table-column>
  97. </el-table>
  98. </div>
  99. <div class="pageBox">
  100. <el-pagination
  101. v-model:current-page="queryParams.pageNo"
  102. :page-size="queryParams.pageSize"
  103. background
  104. layout="total, prev, pager, next, jumper"
  105. :total="total"
  106. @current-change="handleCurrentChange"
  107. />
  108. </div>
  109. </div>
  110. <el-dialog v-model="dialogVisible" :title="dialogTitle" width="660px" align-center>
  111. <el-form
  112. ref="ruleFormRef"
  113. style="width: 600px"
  114. :model="ruleForm"
  115. label-width="auto"
  116. class="demo-ruleForm"
  117. status-icon
  118. >
  119. <el-form-item label="项目名称" prop="name">
  120. <el-input v-model="formData.xmmc" />
  121. </el-form-item>
  122. <el-row :gutter="20">
  123. <el-col :span="12">
  124. <el-form-item label="跟踪人员" prop="region">
  125. <UserOrgTree
  126. v-model="formData.gzryId"
  127. placeholder="请选择跟踪人员"
  128. @node-click="(item) => treeNodeClick(item, 'gzry')"
  129. />
  130. </el-form-item>
  131. </el-col>
  132. <el-col :span="12">
  133. <el-form-item label="甲方" prop="name">
  134. <el-input v-model="formData.jf" />
  135. </el-form-item>
  136. </el-col>
  137. </el-row>
  138. <el-row :gutter="20">
  139. <el-col :span="12">
  140. <el-form-item label="预估金额(万元)" prop="name">
  141. <el-input v-model="formData.ygje" />
  142. </el-form-item>
  143. </el-col>
  144. <el-col :span="12">
  145. <el-form-item label="甲方对接人" prop="name">
  146. <el-input v-model="formData.jfdjr" />
  147. </el-form-item>
  148. </el-col>
  149. </el-row>
  150. <el-row :gutter="20">
  151. <el-col :span="12">
  152. <el-form-item label="项目归属部门" prop="region">
  153. <DeptTree
  154. v-model="formData.xmbmId"
  155. @node-click="(item) => treeNodeClick(item, 'xmbm')"
  156. placeholder="请选择部门"
  157. />
  158. </el-form-item>
  159. </el-col>
  160. <el-col :span="12">
  161. <el-form-item label="行政区" prop="region">
  162. <DistrictTree
  163. class="form-item-disable-style"
  164. v-model="formData.xzqdm"
  165. @node-click="(item) => treeNodeClick(item, 'xzqmc')"
  166. style="width: 100%"
  167. />
  168. </el-form-item>
  169. </el-col>
  170. </el-row>
  171. <el-row :gutter="20">
  172. <el-col :span="12">
  173. <el-form-item label="状态" prop="region">
  174. <el-select v-model="formData.zt" placeholder="请选择状态" style="width: 100%">
  175. <el-option label="谋划" value="0" />
  176. <el-option label="待上会" value="1" />
  177. <el-option label="待招标" value="2" />
  178. </el-select>
  179. </el-form-item>
  180. </el-col>
  181. <el-col :span="12">
  182. <el-form-item label="谁可见" prop="region">
  183. <UserOrgTree v-model="visibleUserIds" :multiple="true" placeholder="请选择跟谁可见" />
  184. </el-form-item>
  185. </el-col>
  186. </el-row>
  187. <el-form-item label="备注" prop="desc">
  188. <el-input v-model="formData.bz" type="textarea" />
  189. </el-form-item>
  190. </el-form>
  191. <template #footer>
  192. <div class="dialog-footer">
  193. <el-button @click="dialogVisible = false">关闭</el-button>
  194. <el-button type="primary" @click="saveProjectTracking"> 保存 </el-button>
  195. </div>
  196. </template>
  197. </el-dialog>
  198. </div>
  199. </template>
  200. <script setup lang="ts">
  201. import { DICT_TYPE, getDictLabel } from '@/utils/dict'
  202. import { IFormType, useMixins, infoList, user } from './common'
  203. import request from '@/config/axios'
  204. import { getAssetURL } from '@/utils/auth'
  205. import UserOrgTree from '@/views/OaSystem/components/UserOrgTree/index.vue'
  206. import DeptTree from '@/views/OaSystem/components/DeptTree/index.vue'
  207. import DistrictTree from '@/views/OaSystem/components/DistrictTree/index.vue'
  208. defineOptions({ name: 'ProjectTrack' })
  209. const ztMap = {
  210. '0': '谋划',
  211. '1': '待上会',
  212. '2': '待招标'
  213. }
  214. const visibleUserIds = ref<string[]>([])
  215. const tableRef: any = ref(null)
  216. const tableHeight: any = ref(0)
  217. const { queryParams, formData, initFormData } = useMixins()
  218. const handleCurrentChange = (pageNo: number) => {
  219. queryParams.pageNo = pageNo
  220. queryProjectTrackByPage()
  221. }
  222. /**
  223. * 项目跟踪:新增、编辑
  224. */
  225. const dialogTitle = ref<string>('项目跟踪填报')
  226. const dialogVisible = ref<boolean>(false)
  227. const addOrEditHandle = (row?: IFormType) => {
  228. dialogVisible.value = true
  229. if (!row) {
  230. dialogTitle.value = '项目跟踪填报'
  231. initFormData()
  232. visibleUserIds.value = []
  233. } else {
  234. dialogTitle.value = '项目跟踪编辑'
  235. queryProjectTrackByDetail(row['id']).then((result) => {
  236. initFormData(result as any)
  237. visibleUserIds.value = result['visibleUserIds'].split(',')
  238. })
  239. }
  240. }
  241. const treeNodeClick = (item, type: string) => {
  242. if (!item) return
  243. formData.value[type] = item['label'] || item['name']
  244. }
  245. const saveProjectTracking = async (): Promise<void> => {
  246. const urlApi = `/projectTracking/save`
  247. const sendData = {
  248. ...formData.value
  249. }
  250. sendData['visibleUserIds'] = visibleUserIds.value.join(',')
  251. const result = await request.post({ url: urlApi, data: sendData }, '/business')
  252. if (result) {
  253. searchHandle()
  254. dialogVisible.value = false
  255. }
  256. }
  257. const switchChange = (item) => {
  258. updateStatus({
  259. id: item['id'],
  260. status: item['status']
  261. })
  262. }
  263. const updateStatus = async (data: { id: string; status: string }): Promise<void> => {
  264. const urlApi = `/update-status`
  265. return await request.put({ url: urlApi, data: data }, '/business')
  266. }
  267. const tableData = ref<Array<any>>([])
  268. const total = ref<number>()
  269. const searchHandle: () => void = () => {
  270. queryParams.pageNo = 1
  271. queryProjectTrackingSummary()
  272. queryProjectTrackByPage()
  273. }
  274. const queryProjectTrackByPage = async (): Promise<void> => {
  275. const urlApi = `/projectTracking/page`
  276. const sendData = {
  277. ...queryParams
  278. }
  279. const result = await request.get({ url: urlApi, params: sendData }, '/business')
  280. tableData.value = result['list']
  281. total.value = result['total']
  282. }
  283. const queryProjectTrackByDetail = async (id: string): Promise<void> => {
  284. const urlApi = `/projectTracking/getById`
  285. const sendData = {
  286. id
  287. }
  288. return await request.get({ url: urlApi, params: sendData }, '/business')
  289. }
  290. queryProjectTrackByPage()
  291. /**
  292. * 项目金额、项目个数汇总
  293. */
  294. const queryProjectTrackingSummary = async (): Promise<void> => {
  295. const urlApi = `/projectTracking/summary`
  296. const sendData = {
  297. ...queryParams
  298. }
  299. const result = await request.get({ url: urlApi, params: sendData }, '/business')
  300. infoList[0]['num'] = result ? result.amount ?? 0 : 0
  301. infoList[1]['num'] = result ? result.nums ?? 0 : 0
  302. }
  303. queryProjectTrackingSummary()
  304. onMounted(() => {
  305. tableHeight.value = tableRef.value.clientHeight
  306. })
  307. </script>
  308. <style lang="scss" scoped>
  309. :deep(.el-radio) {
  310. margin-right: 10px;
  311. }
  312. </style>