index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. <template>
  2. <!-- 發文資料管理 -->
  3. <div>
  4. <!-- 功能欄 -->
  5. <functionBar class="F_bar" @getList="getFileList"></functionBar>
  6. <div>
  7. <div class="container" fluid></div>
  8. <div style="margin-left: 12%; margin-top: 15px; color: black; width: 80%">
  9. <b-row>
  10. <!-- 篩選條件選項 -->
  11. <b-col cols="2">
  12. <div style="margin-top: 9px; text-align: right">篩選條件:</div>
  13. </b-col>
  14. <b-col cols="6">
  15. <!-- 多選下拉框 -->
  16. <multiselect
  17. v-model="searchCondition.keyword"
  18. tag-placeholder="加入欄位"
  19. placeholder="可輸入檔案名稱或單位名稱"
  20. :options="keywords"
  21. :multiple="true"
  22. :showNoOptions="false"
  23. :taggable="true"
  24. @tag="addTagKeyword"
  25. ></multiselect>
  26. </b-col>
  27. <b-col cols="2">
  28. <!-- 運算子選項 -->
  29. <b-form-select v-model="searchCondition.operator" :options="operators"></b-form-select>
  30. </b-col>
  31. <b-col cols="2" style="padding: 0">
  32. <b-button class="btn_search" style="float: left; margin-top: 4px" @click="filterList">篩選</b-button>
  33. </b-col>
  34. </b-row>
  35. </div>
  36. <div style="width:90%;overflow: auto;margin-left:80px;height:600px;margin-top: 50px;">
  37. <!-- 表格 -->
  38. <b-table
  39. :items="relateFileList"
  40. :fields="fields"
  41. :filter="filter"
  42. thead-class="thClass"
  43. class="text-center"
  44. ref="selectableTable"
  45. responsive="sm"
  46. striped
  47. bordered
  48. fixed
  49. :per-page="perPage"
  50. :current-page="currentPage"
  51. :sort-desc.sync="sortDesc"
  52. :sort-by.sync="sortBy"
  53. sticky-header="577px"
  54. >
  55. <!-- 表頭 -->
  56. <template #head()="{ label, field: { key, sortable } }">
  57. <span style="font-weight: normal; color: white; font-size: 15px">{{ label }}</span>
  58. <template v-if="sortable">
  59. <b-icon font-scale="1.3" v-if="sortBy !== key" icon="arrow-down-up"></b-icon>
  60. <b-icon font-scale="1.3" v-else-if="sortDesc" icon="arrow-down"></b-icon>
  61. <b-icon font-scale="1.3" v-else icon="arrow-up"></b-icon>
  62. </template>
  63. </template>
  64. <!-- 表身 -->
  65. <!-- 序號 -->
  66. <template #cell(serial_number)="data">
  67. <span style="font-weight: normal; color: black; font-size: 15px">
  68. {{ (currentPage - 1) * perPage + data.index + 1 }}
  69. </span>
  70. </template>
  71. <!-- 檔案名稱 -->
  72. <template #cell(name)="data">
  73. <a style="font-weight: normal; color: blue; font-size: 15px" :href="data.item.src" target="_blank">
  74. {{ data.value }}
  75. </a>
  76. </template>
  77. <!-- 發文日期 -->
  78. <template #cell(postDay)="data">
  79. <span style="font-weight: normal; color: black; font-size: 15px">{{ getFormattedDate(data.value) }}</span>
  80. </template>
  81. <!-- 單位名稱 -->
  82. <template #cell(department_classification)="data">
  83. <span style="font-weight: normal; color: black; font-size: 15px">{{ data.value }}</span>
  84. </template>
  85. <!-- 類型 -->
  86. <template #cell(icon)="data">
  87. <img class="ml-3 m-0" style="width:30px;height:auto;display:inline-block" :src="data.item.icon">
  88. </template>
  89. <!-- 大小 -->
  90. <template #cell(size)="data">
  91. <span style="font-weight: normal; color: black; font-size: 15px" v-if="data.value / 1024 / 1024 > 1">
  92. {{ (data.value / 1024 / 1024).toFixed(1) }}&nbsp;MB
  93. </span>
  94. <span v-else>{{ (data.value / 1024).toFixed(1) }}&nbsp;KB</span>
  95. </template>
  96. </b-table>
  97. </div>
  98. <!-- 分頁符號 -->
  99. <b-pagination v-model="currentPage" pills :total-rows="rows" :per-page="perPage" aria-controls="my-table"></b-pagination>
  100. </div>
  101. </div>
  102. </template>
  103. <script>
  104. import functionBar from '@/views/DocumentManagement/MainPage/functionBar.vue'
  105. import { mapState, mapActions } from 'vuex'
  106. import Multiselect from 'vue-multiselect'
  107. import moment from 'moment'
  108. import fileType from '@/util/fileType.js'
  109. import 'vue-multiselect/dist/vue-multiselect.min.css'
  110. export default {
  111. components: {
  112. functionBar,
  113. Multiselect,
  114. modal: () => import('@/views/Modal/index.vue')
  115. },
  116. data () {
  117. return {
  118. keywords: [],
  119. filter: null,
  120. selected: [],
  121. perPage: 8,
  122. currentPage: 1,
  123. sortBy: null,
  124. sortDesc: false,
  125. fields: [
  126. {
  127. key: 'serial_number',
  128. label: '序號',
  129. sortable: false,
  130. tdClass: 'align-middle',
  131. thStyle: { background: '#1d325f', color: '#ffffff', width: '10%' }
  132. },
  133. {
  134. key: 'name',
  135. label: '檔案名稱',
  136. sortable: false,
  137. tdClass: 'align-middle',
  138. thStyle: { background: '#1d325f', color: '#ffffff', width: '30%' }
  139. },
  140. {
  141. key: 'postDay',
  142. label: '發文日期',
  143. sortable: true,
  144. tdClass: 'align-middle',
  145. thStyle: { background: '#1d325f', color: '#ffffff', width: '15%' }
  146. },
  147. {
  148. key: 'department_classification',
  149. label: '單位名稱',
  150. sortable: true,
  151. tdClass: 'align-middle',
  152. thStyle: { background: '#1d325f', color: '#ffffff', width: '20%' }
  153. },
  154. {
  155. key: 'icon',
  156. label: '類型',
  157. sortable: false,
  158. tdClass: 'align-middle',
  159. thStyle: { background: '#1d325f', color: '#ffffff', width: '15%' }
  160. },
  161. {
  162. key: 'size',
  163. label: '檔案大小',
  164. sortable: false,
  165. tdClass: 'align-middle',
  166. thStyle: { background: '#1d325f', color: '#ffffff', width: '10%' }
  167. }
  168. ],
  169. operators: [
  170. { value: 'and', text: 'and' },
  171. { value: 'or', text: 'or' }
  172. ],
  173. searchCondition: {
  174. operator: 'and',
  175. keyword: []
  176. },
  177. relateFileList: []
  178. }
  179. },
  180. async mounted () {
  181. await this.getPostFileManagement(this.currentUser.defaultTender)
  182. await this.lookupTender(this.currentUser.defaultTender)
  183. await this.getOtherList(this.currentUser.defaultTender)
  184. this.getFileList()
  185. console.log(this.relateFileList)
  186. },
  187. methods: {
  188. ...mapActions('tenders', ['getPostFileManagement', 'getOtherList', 'lookupPostFileSearch', 'lookupTender']),
  189. getFormattedDate (date) {
  190. // 轉換日期格式
  191. let d = null
  192. if (date) {
  193. return moment(date).format('YYYY-MM-DD')
  194. } else {
  195. return d
  196. }
  197. },
  198. addTagKeyword (newTag) {
  199. this.searchCondition.keyword.push(newTag)
  200. },
  201. async filterList () {
  202. if (this.searchCondition.keyword.length === 0) {
  203. alert('輸入關鍵字')
  204. } else {
  205. let searchList = await this.lookupPostFileSearch({
  206. operator: this.searchCondition.operator,
  207. keyword:
  208. this.searchCondition.keyword.length === 0
  209. ? []
  210. : this.searchCondition.keyword
  211. })
  212. if (searchList.length !== 0) {
  213. this.relateFileList = searchList.map(item => ({
  214. ...item,
  215. icon: fileType(item.mime)
  216. }))
  217. } else {
  218. this.relateFileList = []
  219. }
  220. }
  221. },
  222. async getFileList () {
  223. this.relateFileList = []
  224. for (let i = 0; i < this.postFileManagementList.length; i++) {
  225. const element = this.postFileManagementList[i]
  226. const docFile = element.docFile
  227. const { name, mime, size, src } = docFile[0]
  228. if (docFile && docFile.length > 0 && docFile[0].name) {
  229. this.relateFileList.push({
  230. _id: element._id,
  231. postDay: element.postDay,
  232. department_classification: element.department_classification,
  233. name,
  234. mime,
  235. size,
  236. src,
  237. icon: fileType(mime)
  238. })
  239. }
  240. }
  241. console.log(this.relateFileList)
  242. }
  243. },
  244. computed: {
  245. rows () {
  246. return this.relateFileList.length
  247. },
  248. ...mapState({
  249. officialDocument: (state) => state.officialDocument.officialDocument,
  250. postFileManagementList: (state) => state.tenders.postFileManagementList,
  251. currentUser: state => state.user.current,
  252. tenderList: (state) => state.tenders.tenderList,
  253. postFileManagement: (state) => state.tenders.tenderList.postFileManagement
  254. })
  255. },
  256. watch: {
  257. // 監視 postFileManagementList 的變動,當資料變動時,自動更新檔案列表
  258. postFileManagementList: {
  259. handler () {
  260. this.getFileList()
  261. },
  262. deep: true // 監視所有層級的變動,如果檔案列表是嵌套的也會監視到
  263. }
  264. }
  265. }
  266. </script>
  267. <style>
  268. .F_bar {
  269. z-index: 999;
  270. }
  271. .thClass {
  272. background-color: #1d325f;
  273. color: white;
  274. }
  275. .table.b-table > thead > tr > th,
  276. .table.b-table > tfoot > tr > td {
  277. background-image: none !important;
  278. }
  279. </style>
  280. <style lang="scss" scoped>
  281. /deep/.popover{
  282. padding: 10px;
  283. max-width: 450px;
  284. text-align: left;
  285. background-color: white;
  286. }
  287. /deep/ .popover-header{
  288. font-size: 18px;
  289. color: black;
  290. }
  291. /deep/ .popover-body{
  292. font-size: 16px;
  293. color: black;
  294. }
  295. /deep/ .align-middle {
  296. max-width: 200px;
  297. white-space: normal !important;
  298. }
  299. /deep/ .truncate {
  300. width: 50px;
  301. white-space: nowrap;
  302. overflow: hidden;
  303. text-overflow: ellipsis;
  304. }
  305. .container {
  306. height: 50px;
  307. margin-top: 10px;
  308. margin-left: 5%;
  309. padding-top: 10px;
  310. padding-left: 1%;
  311. padding-right: 1%;
  312. }
  313. .text-center {
  314. width: 100%;
  315. height: 100%;
  316. }
  317. .btns2 {
  318. float: right;
  319. margin-right: 5%;
  320. }
  321. .btn_refresh {
  322. background-color: #f7fafc;
  323. font-size: 14px;
  324. padding-left: 7px;
  325. padding-right: 7px;
  326. padding-top: 5px;
  327. padding-bottom: 5px;
  328. margin-left: 10px;
  329. color: #1d325f;
  330. box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.1);
  331. }
  332. .btn_refresh:hover {
  333. color: black;
  334. background-color: rgb(228, 228, 228);
  335. transform: scale(1.1);
  336. }
  337. .btn_search {
  338. background-color: rgb(75, 102, 255);
  339. font-size: 15px;
  340. padding-left: 10px;
  341. padding-right: 10px;
  342. padding-top: 6px;
  343. padding-bottom: 6px;
  344. color: white;
  345. box-shadow: 2px 2px 10px rgba(0, 0, 0, 0.1);
  346. }
  347. .btn_search:hover {
  348. color: black;
  349. background-color: rgb(228, 228, 228);
  350. transform: translateY(1);
  351. }
  352. .pagination {
  353. display: flex;
  354. align-items: center;
  355. justify-content: center;
  356. padding-bottom: 20px;
  357. margin-top: 20px;
  358. color: #383838;
  359. }
  360. .form-control {
  361. color: black;
  362. }
  363. .custom-select {
  364. color: black;
  365. }
  366. .table thead th {
  367. font-size: 15px;}
  368. </style>