index.vue 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. <template>
  2. <div class="data-query scroll-y">
  3. <div class="data-query-header">
  4. <div class="manageTitle">{{ title }}</div>
  5. <el-form
  6. ref="formRef"
  7. :model="formData"
  8. class="data-query-form"
  9. :rules="rules"
  10. @submit.native.prevent
  11. >
  12. <div v-if="name !== 'waybill'" class="form-left">
  13. <el-form-item prop="startDate">
  14. <el-date-picker
  15. v-model="formData.startDate"
  16. format="YYYY-MM-DD"
  17. value-format="YYYY-MM-DD"
  18. size="default"
  19. type="date"
  20. placeholder="开始日期"
  21. :prefix-icon="datePreTitle('开始')"
  22. :clearable="false"
  23. />
  24. </el-form-item>
  25. <el-form-item prop="endDate">
  26. <el-date-picker
  27. v-model="formData.endDate"
  28. format="YYYY-MM-DD"
  29. value-format="YYYY-MM-DD"
  30. :disabled-date="disabledEndDate"
  31. size="default"
  32. type="date"
  33. placeholder="结束日期"
  34. :prefix-icon="datePreTitle('结束')"
  35. :clearable="false"
  36. />
  37. </el-form-item>
  38. </div>
  39. <div class="form-right">
  40. <el-form-item prop="keyWords">
  41. <el-input
  42. v-model.trim="formData.keyWords"
  43. size="default"
  44. placeholder="请输入要搜索的内容"
  45. :prefix-icon="Search"
  46. clearable
  47. @keyup.enter.prevent="dataQuery"
  48. />
  49. </el-form-item>
  50. </div>
  51. </el-form>
  52. <el-button size="default" type="primary" @click="dataQuery"
  53. >搜索</el-button
  54. >
  55. <ColumnSet
  56. :table-columns="tableColumns"
  57. @checked-submit="columnChecked"
  58. />
  59. </div>
  60. <div
  61. v-loading="loading"
  62. element-loading-text="拼命加载中"
  63. element-loading-spinner="el-icon-loading"
  64. element-loading-background="rgba(0, 0, 0, 0.8)"
  65. class="data-query-table"
  66. >
  67. <SimpleTable
  68. ref="tableRef"
  69. :data="tableData"
  70. :columns="filteredColumns"
  71. :cell-class-name="cellClass"
  72. :column-props="{ formatter }"
  73. @cell-click="cellClickHandler"
  74. />
  75. </div>
  76. </div>
  77. </template>
  78. <script setup lang="tsx">
  79. import { Search } from '@element-plus/icons-vue'
  80. import ColumnSet from '@/components/ColumnSet/index.vue'
  81. import SimpleTable from '@/components/SimpleTable/index.vue'
  82. import { ElMessage, FormInstance } from 'element-plus'
  83. import { parseTime } from '@/utils/validate'
  84. import { useTable } from './useTable'
  85. import { useTableColumnSet } from '@/hooks/useTableColumnSet'
  86. import { CommonTableFormatter } from '~/common'
  87. const props = defineProps({
  88. name: {
  89. type: String,
  90. required: true,
  91. },
  92. title: {
  93. type: String,
  94. required: true,
  95. },
  96. })
  97. const today = parseTime(new Date(), '{y}-{m}-{d}') as string
  98. const formData = reactive({
  99. startDate: props.name === 'waybill' ? null : today,
  100. endDate: props.name === 'waybill' ? null : today,
  101. keyWords: '',
  102. })
  103. watchEffect(() => {
  104. if (!formData.startDate || !formData.endDate) {
  105. return
  106. }
  107. const start = new Date(formData.startDate).getTime()
  108. const end = new Date(formData.endDate).getTime()
  109. if (start > end) {
  110. ElMessage.warning('开始时间不能晚于结束时间')
  111. formData.endDate = ''
  112. }
  113. if (start <= end - 2 * 24 * 60 * 60 * 1000) {
  114. ElMessage.warning('间隔不能超过2天')
  115. formData.endDate = ''
  116. }
  117. })
  118. const disabledEndDate = (endDate: Date) => {
  119. const start = new Date(formData.startDate + ' 00:00:00').getTime()
  120. const end = endDate.getTime()
  121. return start > end || start <= end - 2 * 24 * 60 * 60 * 1000
  122. }
  123. const datePreTitle = (title: string) => {
  124. return <div class="date-pre-title">{title}:</div>
  125. }
  126. const keyWordsValidator = (rule: any, value: any, callback: any) => {
  127. const searchTitleMap = {
  128. flight: '航班号',
  129. waybill: '运单号',
  130. freight: '货物编码',
  131. }
  132. const searchTitle = searchTitleMap[props.name] ?? '关键词'
  133. if (!value) {
  134. if (['flight'].includes(props.name)) {
  135. return callback()
  136. } else {
  137. return callback(new Error(`请输入${searchTitle}`))
  138. }
  139. }
  140. const regsMap: { [x: string]: RegExp[] } = {
  141. // flight: [/^[A-Za-z0-9][A-Za-z][0-9]{3,4}$/, /^[0-9]{3,4}$/],
  142. flight: [/^[A-Za-z0-9]{1,6}$/],
  143. waybill: [/^[0-9]{3}\-[0-9]{8}/],
  144. freight: [/^[0-9]{5}$/, /^[0-9]{3}\-[0-9]{8}\-[0-9]{5}$/],
  145. }
  146. const regs = regsMap[props.name] ?? []
  147. const notMatched = regs.length && regs.every(reg => !reg.test(value))
  148. if (notMatched) {
  149. return callback(new Error(`请输入正确的${searchTitle}`))
  150. }
  151. return callback()
  152. }
  153. const rules = {
  154. startDate: [{ required: true, message: '请选择开始日期', trigger: 'blur' }],
  155. endDate: [{ required: true, message: '请选择结束日期', trigger: 'blur' }],
  156. keyWords: [{ validator: keyWordsValidator, trigger: 'blur' }],
  157. }
  158. const formRef = ref<FormInstance | null>()
  159. const dataQuery = () => {
  160. formRef.value?.validate(valid => {
  161. if (valid) {
  162. getTableData()
  163. }
  164. })
  165. }
  166. const loading = ref(false)
  167. const { tableColumns, tableData, getTableData } = useTable(
  168. props.name,
  169. formData,
  170. loading
  171. )
  172. const { filteredColumns, columnChecked } = useTableColumnSet(tableColumns)
  173. const formatter: CommonTableFormatter = (row, column, cellValue, index) => {
  174. const value = String(cellValue ?? '').trim()
  175. if (column.property.includes('Time')) {
  176. return value.replace('T', '\n')
  177. }
  178. return value
  179. }
  180. const cellClass = ({ row, column, rowIndex, columnIndex }) => {
  181. const classes: string[] = []
  182. switch (props.name) {
  183. case 'flight':
  184. if (['flightNO'].includes(column.property) && row[column.property]) {
  185. classes.push('cell-click')
  186. }
  187. break
  188. case 'waybill':
  189. if (['stockCode'].includes(column.property) && row[column.property]) {
  190. classes.push('cell-click')
  191. }
  192. break
  193. case 'freight':
  194. break
  195. default:
  196. break
  197. }
  198. return classes.join(' ')
  199. }
  200. const router = useRouter()
  201. const cellClickHandler = (row, column, cell, event) => {
  202. switch (props.name) {
  203. case 'flight': {
  204. switch (column.property) {
  205. case 'flightNO': {
  206. if (
  207. !row.flightAllNO ||
  208. !row.flightDate ||
  209. !['INT', 'DOM'].includes(row.DIType) ||
  210. typeof row.FFID !== 'string' ||
  211. !['A', 'D'].includes(row.FFID.at(-1))
  212. ) {
  213. ElMessage.error('航班信息缺失!')
  214. return
  215. }
  216. const viewName = `${row.DIType === 'DOM' ? '' : 'International'}${
  217. row.FFID.at(-1) === 'D' ? 'Departure' : 'Arrival'
  218. }Flight`
  219. router.push({
  220. path: `/dataQuery/flightQuery/${viewName}`,
  221. query: {
  222. flightNO: row.flightAllNO,
  223. flightDate: row.flightDate,
  224. },
  225. })
  226. break
  227. }
  228. default:
  229. break
  230. }
  231. break
  232. }
  233. case 'waybill': {
  234. switch (column.property) {
  235. case 'stockCode': {
  236. if (
  237. !row.stockCode ||
  238. !row.flightDate ||
  239. !['INT', 'DOM'].includes(row.DIType) ||
  240. typeof row.FFID !== 'string' ||
  241. !['A', 'D'].includes(row.FFID.at(-1))
  242. ) {
  243. ElMessage.error('运单信息缺失!')
  244. return
  245. }
  246. const viewName = `${row.DIType === 'DOM' ? '' : 'International'}${
  247. row.FFID.at(-1) === 'D' ? 'Departure' : 'Arrival'
  248. }Waybill`
  249. router.push({
  250. path: `/dataQuery/waybillQuery/${viewName}`,
  251. query: {
  252. waybillNO: row.stockCode,
  253. flightDate: row.flightDate,
  254. },
  255. })
  256. break
  257. }
  258. }
  259. break
  260. }
  261. case 'freight':
  262. break
  263. default:
  264. break
  265. }
  266. }
  267. </script>
  268. <style lang="scss" scoped>
  269. .data-query {
  270. width: 100%;
  271. height: 100%;
  272. display: flex;
  273. flex-direction: column;
  274. &-header {
  275. width: 100%;
  276. height: 32px;
  277. margin: 12px 0;
  278. display: flex;
  279. }
  280. &-form :deep {
  281. margin-right: 12px;
  282. flex: 1;
  283. display: flex;
  284. justify-content: flex-end;
  285. .form-left {
  286. flex: 1;
  287. display: flex;
  288. .el-form-item {
  289. width: 168px;
  290. margin-right: 8px;
  291. }
  292. }
  293. .form-right {
  294. display: flex;
  295. justify-content: flex-end;
  296. .el-form-item {
  297. width: 280px;
  298. }
  299. }
  300. .el-form-item {
  301. margin: 0;
  302. .el-input__inner {
  303. font-size: 14px;
  304. font-family: Helvetica, Microsoft YaHei;
  305. color: #303133;
  306. }
  307. .el-date-editor {
  308. .el-input__prefix {
  309. flex-basis: 42px;
  310. padding-left: 15px;
  311. .date-pre-title {
  312. font-style: normal;
  313. font-size: 14px;
  314. font-family: Microsoft YaHei;
  315. color: #303133;
  316. }
  317. }
  318. }
  319. }
  320. }
  321. &-table {
  322. height: 0;
  323. flex: 1;
  324. }
  325. }
  326. </style>