index.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. <template>
  2. <div class="tableTmp">
  3. <div class="tableTmp-add flex">
  4. <div class="manageTitle">{{pageTitle}}</div>
  5. <el-button size="default" @click="handleAdd" plain>新增</el-button>
  6. </div>
  7. <div class="tableTmp-content t24">
  8. <el-table height="100%" v-loading="loading" element-loading-text="拼命加载中" element-loading-spinner="el-icon-loading" element-loading-background="rgba(0, 0, 0, 0.8)" v-el-table-infinite-scroll="load" :data="filteredTableData" stripe :border="true" style="width: 100%">
  9. <el-table-column v-for="(item, index) in tableColsCopy" :sortable="item.needSort ? true : false" :key="index" :prop="item.columnName" :label="item.columnLabel" :show-overflow-tooltip="showOverflowTooltip">
  10. <template #header>
  11. <span class="colTips">
  12. <el-tooltip :content="item.columnDescribe" placement="top">
  13. <span>{{ item.columnLabel }}</span>
  14. </el-tooltip>
  15. </span>
  16. <span v-if="item.needFilters">
  17. <el-popover placement="bottom" trigger="click">
  18. <template #reference>
  19. <el-icon>
  20. <ArrowDownBold />
  21. </el-icon>
  22. </template>
  23. <el-form>
  24. <el-form-item :label="item.columnLabel">
  25. <el-select v-model="filterValues[item.columnName]" size="small" placeholder="筛选" default-first-option filterable clearable>
  26. <el-option v-for="(option, optionIndex) in tableDataFilters[item.columnName]" :key="option.value + optionIndex" :value="option.value" :label="option.text" />
  27. </el-select>
  28. </el-form-item>
  29. </el-form>
  30. </el-popover>
  31. </span>
  32. </template>
  33. </el-table-column>
  34. <el-table-column fixed="right" label="操作" :width="fixedWidth">
  35. <template #default="scope">
  36. <el-button type="primary" @click="handleEdit(scope.row)" size="small">编辑</el-button>
  37. <el-button type="danger" @click="handleRemove(scope.row)" size="small">删除</el-button>
  38. </template>
  39. </el-table-column>
  40. </el-table>
  41. </div>
  42. <!--新增/编辑-->
  43. <Dialog :flag="editFlag" width="650px" :msgTitle="editTitle" @submitForm="submitForm(ruleFormRef)" @resetForm="resetForm(ruleFormRef)" :show-flag="true">
  44. <el-form ref="ruleFormRef" :model="tableForm" :label-width="labelWidth" class="demo-ruleForm">
  45. <el-row :gutter="20">
  46. <el-col v-for="(item, index) in tableColsCopy" :key="index" :span="rows">
  47. <el-form-item :label="item.columnLabel">
  48. <template v-if="item.listqueryTemplateID || item.listqueryTemplateID == 0">
  49. <el-select class="input-shadow" size="default" filterable default-first-option style="width: 100%" v-model="tableForm[item.columnName]" placeholder="请选择" clearable @clear="tableForm[item.columnName] = ''">
  50. <el-option v-for="citem in tableOptions[item.columnName]" :key="citem.v ? citem.v : citem.planDepartureApt" :label="citem.k ? citem.k : citem.planDepartureApt" :value="citem.setlabel === 'positionDescribe' ? citem.v : citem.v != undefined ? citem.v : citem.planDepartureApt">
  51. </el-option>
  52. </el-select>
  53. </template>
  54. <template v-else-if="item.dataType == 'longtext'">
  55. <el-input size="default" :rows="1" type="textarea" v-model="tableForm[item.columnName]"></el-input>
  56. </template>
  57. <template v-else-if="item.dataType == 'datetime'">
  58. <el-date-picker value-format="yyyy-MM-dd HH:mm:ss" v-model="tableForm[item.columnName]" :rows="1" type="datetime" placeholder="选择日期时间">
  59. </el-date-picker>
  60. </template>
  61. <template v-else-if="item.dataType == 'number'">
  62. <el-input size="default" v-model.number="tableForm[item.columnName]" onkeyup="value=value.replace(/[^1-9]/g,'')"></el-input>
  63. </template>
  64. <template v-else>
  65. <el-input size="default" v-model="tableForm[item.columnName]"></el-input>
  66. </template>
  67. </el-form-item>
  68. </el-col>
  69. </el-row>
  70. </el-form>
  71. </Dialog>
  72. <!---删除-->
  73. <Dialog type="del" :flag="delFlag" msgTitle="删除" :delName="delTitle" @delRest="delRest" @delRemove="delRemove" />
  74. </div>
  75. </template>
  76. <script setup lang="ts">
  77. import { ref, onBeforeMount, computed } from "vue";
  78. import * as _ from "lodash";
  79. import type { TableColumnCtx } from "element-plus/es/components/table/src/table-column/defaults";
  80. import { Query, GeneralDataReception } from "@/api/webApi";
  81. import { ElMessage, FormInstance, FormRules } from "element-plus";
  82. import Dialog from "@/components/dialog/index.vue";
  83. const props = defineProps({
  84. tableId: {
  85. type: Number,
  86. default: 0,
  87. },
  88. dataContent: {
  89. type: Array,
  90. default: () => [],
  91. },
  92. fixedWidth: {
  93. type: String || Number,
  94. default: "150px",
  95. },
  96. // 不换行,溢出隐藏
  97. showOverflowTooltip: {
  98. type: Boolean,
  99. default: false,
  100. },
  101. //弹框-表单文字宽度
  102. labelWidth: {
  103. type: String,
  104. default: "80px",
  105. },
  106. //弹框表单-行数
  107. rows: {
  108. type: Number,
  109. default: 12,
  110. },
  111. });
  112. const page = ref<number>(0); //分页参数
  113. const { dataContent, showOverflowTooltip, fixedWidth, labelWidth, rows } =
  114. props;
  115. const ruleFormRef = ref<FormInstance>();
  116. const loading = ref(false);
  117. const noMore = ref(false);
  118. const queryId = ref<any>(null);
  119. const serviceId = ref<any>(null);
  120. const tableData = ref<any>([]);
  121. const tableCols = ref<any>([]);
  122. const tableDataCopy = ref<any>([]);
  123. const tableColsCopy = ref<any>([]); //表头数据缓存
  124. const tableForm = ref<any>({}); //弹框新增/编辑数据
  125. const filterValues = ref<any>({}); //表头-下拉-选中数据
  126. const tableDataFilters = ref<any>({}); //表头-下拉数据
  127. const tableGroups = ref<any>([]); //表格分组数据
  128. const pageTitle = ref<any>("");
  129. const rowTitle = ref("");
  130. const delTitle = ref("");
  131. const delFlag = ref(false);
  132. const editTitle = ref("编辑");
  133. const editType = ref("add");
  134. const editFlag = ref(false);
  135. const delObj = ref<any>({});
  136. const tableOptions = ref<any>({}); //弹框-下来数据缓存
  137. //获取表格数据
  138. const getQuery = async (id) => {
  139. try {
  140. loading.value = true;
  141. const { code, returnData } = await Query({
  142. id,
  143. needPage: ++page.value,
  144. dataContent,
  145. });
  146. if (code == 0) {
  147. if (returnData.listValues.length === 0) {
  148. page.value--;
  149. noMore.value = true;
  150. loading.value = false;
  151. }
  152. const titleColumn = returnData.columnSet.find(
  153. (item) => item.needShow === 1
  154. );
  155. if (titleColumn) {
  156. rowTitle.value = titleColumn.columnName;
  157. }
  158. tableData.value.push(...returnData.listValues);
  159. tableCols.value = returnData.columnSet;
  160. serviceId.value = returnData.submitID;
  161. setTimeout(() => {
  162. initTableData();
  163. }, 100);
  164. } else {
  165. page.value--;
  166. loading.value = false;
  167. }
  168. } catch (error) {
  169. page.value--;
  170. loading.value = false;
  171. }
  172. };
  173. //初始化表格
  174. const initTableData = () => {
  175. tableColsCopy.value = tableCols.value.filter((item) => item.needShow);
  176. tableDataCopy.value = _.cloneDeep(tableData.value);
  177. const datas = _.cloneDeep(tableColsCopy.value);
  178. datas.forEach(async (item) => {
  179. tableDataFilters.value[item.columnName] = [];
  180. if (item.needGroup) {
  181. tableGroups.value.push(item.columnName);
  182. }
  183. });
  184. setTableFilters(tableData.value, tableDataFilters.value);
  185. };
  186. // 表格添加过滤条件
  187. const setTableFilters = (tableData, filters) => {
  188. const tempSets = {};
  189. Object.keys(filters).forEach((key) => {
  190. tempSets[key] = new Set();
  191. });
  192. tableData.forEach((item) => {
  193. Object.keys(tempSets).forEach((key) => {
  194. (item[key] ?? "") !== "" && tempSets[key].add(String(item[key]));
  195. });
  196. });
  197. Object.keys(tempSets).forEach((key) => {
  198. filters[key] = _.orderBy(
  199. [...tempSets[key]].map((value) => ({
  200. text: value,
  201. value,
  202. })),
  203. (o) => o.value
  204. );
  205. });
  206. };
  207. //表格数据滚动加载
  208. const load = () => {
  209. if (noMore.value) {
  210. return;
  211. }
  212. getQuery(queryId.value);
  213. };
  214. //重置表格
  215. const resetTable = () => {
  216. page.value = 0;
  217. noMore.value = false;
  218. tableData.value = [];
  219. };
  220. //表格筛选下拉
  221. const itemFilters = computed(() => (item) => {
  222. if (item.needFilters) {
  223. const datas = <any>[];
  224. const table = _.cloneDeep(tableData.value);
  225. const key = item.columnName;
  226. table.forEach((citem) => {
  227. datas.push({
  228. text: citem[key],
  229. value: citem[key],
  230. });
  231. });
  232. return datas;
  233. } else {
  234. return [];
  235. }
  236. });
  237. //表格筛选
  238. const filterHandler = (value: string, row, column: TableColumnCtx<any>) => {
  239. const property = column["property"];
  240. return row[property] === value;
  241. };
  242. //表格数据新增弹框
  243. const handleAdd = () => {
  244. editFlag.value = true;
  245. editType.value = "add";
  246. tableForm.value = {};
  247. };
  248. //表格数据编辑弹框
  249. const handleEdit = (row) => {
  250. editFlag.value = true;
  251. editType.value = "edit";
  252. tableForm.value = _.cloneDeep(row);
  253. };
  254. //表格数据删除弹框
  255. const handleRemove = (row) => {
  256. delFlag.value = true;
  257. delObj.value = _.cloneDeep(row);
  258. delTitle.value = row[rowTitle.value];
  259. };
  260. //删除-取消
  261. const delRest = () => {
  262. delFlag.value = false;
  263. };
  264. //删除-确定
  265. const delRemove = () => {
  266. dataChange(3, delObj.value);
  267. delFlag.value = false;
  268. };
  269. //新增/编辑确定
  270. const submitForm = async (formEl: FormInstance | undefined) => {
  271. if (!formEl) return;
  272. await formEl.validate((valid, fields) => {
  273. if (valid) {
  274. if (editType.value == "add") {
  275. dataChange(1, tableForm.value);
  276. } else {
  277. dataChange(2, tableForm.value);
  278. }
  279. editFlag.value = false;
  280. } else {
  281. console.log("error submit!", fields);
  282. }
  283. });
  284. };
  285. //新增/编辑取消
  286. const resetForm = (formEl: FormInstance | undefined) => {
  287. if (!formEl) return;
  288. formEl.resetFields();
  289. editFlag.value = false;
  290. };
  291. //增删改
  292. const dataChange = async (event, data) => {
  293. data.event = event;
  294. const { code, message } = await GeneralDataReception({
  295. serviceId: serviceId.value,
  296. dataContent: JSON.stringify(data),
  297. });
  298. if (code == 0) {
  299. getQuery(queryId.value);
  300. ElMessage.success(message);
  301. } else {
  302. ElMessage.error(message);
  303. }
  304. };
  305. //设置表头-下拉-选中数据
  306. const filteredTableData = computed(() => {
  307. return tableData.value.filter((item) => {
  308. let flag = true;
  309. Object.entries(filterValues.value).forEach(([key, value]) => {
  310. if (value !== "" && item[key] !== value) {
  311. flag = false;
  312. }
  313. });
  314. return flag;
  315. });
  316. });
  317. //获取表格id
  318. onBeforeMount(() => {
  319. const route = useRoute();
  320. const { qid, title } = route.meta;
  321. pageTitle.value = title;
  322. if (qid) {
  323. queryId.value = qid;
  324. }
  325. });
  326. </script>
  327. <style lang="scss" scoped>
  328. .tableTmp {
  329. height: 100%;
  330. &-content {
  331. height: calc(100% - 56px);
  332. :deep .el-table {
  333. .colTips {
  334. color: #333;
  335. font-size: 14px;
  336. }
  337. .is-first-column {
  338. .cell {
  339. color: #333;
  340. font-size: 14px;
  341. }
  342. }
  343. }
  344. }
  345. }
  346. </style>