table-action-modal.vue 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. <template>
  2. <n-modal v-model:show="modalVisible" preset="card" :title="title" style="width: 70%">
  3. <n-form ref="formRef" label-placement="left" :label-width="80" :model="formModel" :rules="rules">
  4. <n-grid :cols="48" :x-gap="18">
  5. <n-form-item-grid-item :span="25" label="指标名称" path="name">
  6. <n-input v-model:value="formModel.name" />
  7. </n-form-item-grid-item>
  8. <n-form-item-grid-item :span="25" label="分类ID" path="category_id">
  9. <n-input-number v-model:value="formModel.category_id" />
  10. </n-form-item-grid-item>
  11. <n-form-item-grid-item :span="25" label="是否展示" path="is_show">
  12. <n-select v-model:value="formModel.is_show" :options="IndicatorsOptions" />
  13. </n-form-item-grid-item>
  14. <n-form-item-grid-item :span="25" label="指标描述" path="description">
  15. <n-input v-model:value="formModel.description" type="textarea" placeholder="请输入指标描述" />
  16. </n-form-item-grid-item>
  17. </n-grid>
  18. <n-space style="display: flex; flex-direction: column">
  19. <n-button type="primary" @click="addEventIndicators">添加指标事件</n-button>
  20. <n-data-table :columns="columns" :data="tableData" />
  21. </n-space>
  22. <n-space class="w-full pt-16px" :size="24" justify="end">
  23. <n-button class="w-72px" @click="closeModal">取消</n-button>
  24. <n-button class="w-72px" type="primary" @click="handleSubmit">确定</n-button>
  25. </n-space>
  26. </n-form>
  27. </n-modal>
  28. </template>
  29. <script setup lang="ts">
  30. import { ref, computed, reactive, watch, h } from 'vue';
  31. import type { FormInst, FormItemRule, DataTableColumns } from 'naive-ui';
  32. import { NButton, NTag, NInput, NInputNumber, NSelect } from 'naive-ui';
  33. import {
  34. EditSelectBoxDataSource,
  35. EditSelectBoxIsShow,
  36. EditSelectBoxTriggerOperation,
  37. IndicatorsOptions,
  38. EditSelectBoxStartTime
  39. } from '@/constants';
  40. import { createRequiredFormRule } from '@/utils';
  41. import { basicEventList, fetchIndicatorsAdd, fetchIndicatorsEdit } from '@/service/api/event';
  42. export interface Props {
  43. /** 弹窗可见性 */
  44. visible: boolean;
  45. /**
  46. * 弹窗类型
  47. * add: 新增
  48. * edit: 编辑
  49. */
  50. type?: 'add' | 'edit';
  51. /** 编辑的表格行数据 */
  52. editData?: BackgroundIndicators.Indicators | null;
  53. }
  54. export type ModalType = NonNullable<Props['type']>;
  55. defineOptions({ name: 'TableActionModal' });
  56. const props = withDefaults(defineProps<Props>(), {
  57. type: 'add',
  58. editData: null
  59. });
  60. interface Emits {
  61. (e: 'update:visible', visible: boolean): void;
  62. }
  63. const emit = defineEmits<Emits>();
  64. const modalVisible = computed({
  65. get() {
  66. return props.visible;
  67. },
  68. set(visible) {
  69. emit('update:visible', visible);
  70. }
  71. });
  72. const titles: Record<ModalType, string> = {
  73. add: '添加指标',
  74. edit: '编辑指标'
  75. };
  76. const title = computed(() => {
  77. return titles[props.type];
  78. });
  79. const formRef = ref<HTMLElement & FormInst>();
  80. type FormModel = Pick<
  81. ApiBackground.Indicators,
  82. 'id' | 'name' | 'category_id' | 'particle_size' | 'is_show' | 'description' | 'event_indicators'
  83. >;
  84. const formModel = reactive<FormModel>(createDefaultFormModel());
  85. const rules: Record<keyof FormModel, FormItemRule | FormItemRule[]> = {
  86. name: createRequiredFormRule('请输入指标字段名'),
  87. particle_size: createRequiredFormRule('请选择指标颗粒度'),
  88. category_id: createRequiredFormRule('请选择分类id'),
  89. description: createRequiredFormRule('请输入字段描述'),
  90. is_show: createRequiredFormRule(),
  91. id: createRequiredFormRule(),
  92. event_indicators: createRequiredFormRule()
  93. };
  94. const createData = (): RowIndicators.Data[] => [
  95. {
  96. event_id: 0,
  97. event_name: '',
  98. trigger_operation: 1,
  99. is_cumulative: 1,
  100. impact_mode: 1,
  101. impact_value: 0,
  102. start_time: 1
  103. }
  104. ];
  105. const tableData = ref(createData());
  106. const selectBoxData: IndicatorsSelectBox.Data = {
  107. cowEventData: [],
  108. triggerOperation: EditSelectBoxTriggerOperation,
  109. isCumulative: EditSelectBoxIsShow,
  110. impactMode: EditSelectBoxDataSource,
  111. impactValue: 0,
  112. eventId: 0,
  113. eventName: '',
  114. startTime: EditSelectBoxStartTime
  115. };
  116. function setIndicatorsEventData(data: ApiBackground.BasicCowField[] | null) {
  117. selectBoxData.cowEventData = data;
  118. }
  119. function getIndicatorsEventData() {
  120. const data = basicEventList();
  121. data.then(res => {
  122. setIndicatorsEventData(res.data);
  123. });
  124. }
  125. const createColumns = (): DataTableColumns<RowIndicators.Data> => [
  126. {
  127. title: '序号',
  128. key: 'orderNum',
  129. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  130. render(row, index) {
  131. return h(
  132. NTag,
  133. {
  134. style: {
  135. marginRight: '6px',
  136. background: 'none',
  137. color: 'rgb(31, 34, 37)'
  138. },
  139. type: 'info',
  140. bordered: false
  141. },
  142. {
  143. default: () => index + 1
  144. }
  145. );
  146. }
  147. },
  148. {
  149. title: '事件名称',
  150. key: 'EventName',
  151. maxWidth: 300,
  152. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  153. render(row, index) {
  154. return h(NSelect, {
  155. options: selectBoxData.cowEventData,
  156. value: tableData.value[index].event_name,
  157. onUpdateValue(value: string) {
  158. tableData.value[index].event_name = value;
  159. }
  160. });
  161. }
  162. },
  163. {
  164. title: '触发操作',
  165. key: 'triggerOperation',
  166. maxWidth: 100,
  167. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  168. render(row, index) {
  169. return h(NSelect, {
  170. options: selectBoxData.triggerOperation,
  171. value: tableData.value[index].trigger_operation,
  172. onUpdateValue(value: number) {
  173. tableData.value[index].trigger_operation = value;
  174. }
  175. });
  176. }
  177. },
  178. {
  179. title: '累加上期',
  180. key: 'cumulative',
  181. maxWidth: 200,
  182. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  183. render(row, index) {
  184. return h(NSelect, {
  185. options: selectBoxData.isCumulative,
  186. value: tableData.value[index].is_cumulative,
  187. onUpdateValue(value: number) {
  188. tableData.value[index].is_cumulative = value;
  189. }
  190. });
  191. }
  192. },
  193. {
  194. title: '变更方法',
  195. key: 'impactMode',
  196. maxWidth: 200,
  197. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  198. render(row, index) {
  199. return h(NSelect, {
  200. options: selectBoxData.impactMode,
  201. value: tableData.value[index].impact_mode,
  202. onUpdateValue(value: number) {
  203. tableData.value[index].impact_mode = value;
  204. }
  205. });
  206. }
  207. },
  208. {
  209. title: '变更值',
  210. key: 'impactValue',
  211. maxWidth: 100,
  212. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  213. render(row, index) {
  214. return h(NInputNumber, {
  215. value: tableData.value[index].impact_value,
  216. showButton: false,
  217. keyboard: {
  218. ArrowDown: false,
  219. ArrowUp: false
  220. },
  221. onUpdateValue(value) {
  222. tableData.value[index].impact_value = value;
  223. }
  224. });
  225. }
  226. },
  227. {
  228. title: '开始时间',
  229. key: 'startTime',
  230. maxWidth: 200,
  231. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  232. render(row, index) {
  233. return h(NSelect, {
  234. options: selectBoxData.startTime,
  235. value: tableData.value[index].start_time,
  236. onUpdateValue(value: number) {
  237. tableData.value[index].start_time = value;
  238. }
  239. });
  240. }
  241. },
  242. {
  243. title: '操作',
  244. key: 'actions',
  245. // eslint-disable-next-line @typescript-eslint/no-unused-vars
  246. render(row, index) {
  247. return [
  248. h(
  249. NButton,
  250. {
  251. // 可在里面写按钮样式
  252. text: true,
  253. style: { marginRight: '10px', color: 'red' },
  254. onClick: () => deleteData(index) // 点击按钮后的回调
  255. },
  256. { default: () => '删除' } // 按钮显示名称
  257. )
  258. ];
  259. }
  260. }
  261. ];
  262. const columns = ref(createColumns());
  263. function addEventIndicators() {
  264. tableData.value.push(createData()[0]);
  265. }
  266. function deleteData(indexKey: number) {
  267. tableData.value.splice(indexKey, 1);
  268. }
  269. function createDefaultFormModel(): FormModel {
  270. return {
  271. id: 0,
  272. name: '',
  273. particle_size: null,
  274. category_id: null,
  275. is_show: null,
  276. description: '',
  277. event_indicators: null
  278. };
  279. }
  280. function handleUpdateFormModel(model: Partial<FormModel>) {
  281. Object.assign(formModel, model);
  282. }
  283. function handleUpdateFormModelByModalType() {
  284. const handlers: Record<ModalType, () => void> = {
  285. add: () => {
  286. const defaultFormModel = createDefaultFormModel();
  287. handleUpdateFormModel(defaultFormModel);
  288. },
  289. edit: () => {
  290. if (props.editData) {
  291. handleUpdateFormModel(props.editData);
  292. if (props.editData.event_indicators) {
  293. tableData.value = props.editData.event_indicators;
  294. }
  295. }
  296. }
  297. };
  298. handlers[props.type]();
  299. }
  300. const closeModal = () => {
  301. tableData.value = [];
  302. modalVisible.value = false;
  303. };
  304. getIndicatorsEventData();
  305. async function handleSubmit() {
  306. formRef.value?.validate();
  307. formModel.event_indicators = tableData.value;
  308. if (props.type === 'add') {
  309. const data = fetchIndicatorsAdd(formModel);
  310. data.then(res => {
  311. if (res.data) {
  312. window.$message?.success(`${titles[props.type]}成功!`);
  313. }
  314. });
  315. }
  316. if (props.type === 'edit') {
  317. const data = fetchIndicatorsEdit(formModel);
  318. data.then(res => {
  319. if (res.data) {
  320. window.$message?.success(`${titles[props.type]}成功!`);
  321. }
  322. });
  323. }
  324. closeModal();
  325. }
  326. watch(
  327. () => props.visible,
  328. newValue => {
  329. if (newValue) {
  330. handleUpdateFormModelByModalType();
  331. }
  332. }
  333. );
  334. </script>
  335. <style scoped></style>