JsonModal.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. <template>
  2. <t-dialog
  3. v-model:visible="props.visible"
  4. :header="$t('JSON值')"
  5. :width="470"
  6. @close="close"
  7. @confirm="confirm"
  8. >
  9. <t-tabs v-model="tabValue" @change="tabChange">
  10. <t-tab-panel :value="1" :label="$t('简单模式')">
  11. <div class="mt-8">
  12. <div class="flex mt-4 one-data" v-for="(d, i) in simpleData">
  13. <t-select-input
  14. class="input-key"
  15. v-if="props.options?.length"
  16. :placeholder="$t('可自定义输入')"
  17. v-model:inputValue="d.key"
  18. :value="d.keyLabel"
  19. v-model:popupVisible="d.keyPopupVisible"
  20. allow-input
  21. clearable
  22. @clear="d.keyLabel = undefined"
  23. @focus="d.keyPopupVisible = true"
  24. @blur="d.keyPopupVisible = false"
  25. @input-change="onKeyInput(d)"
  26. >
  27. <template #panel>
  28. <ul style="padding: 8px 12px">
  29. <li
  30. v-for="item in props.options"
  31. :key="item.value"
  32. @click="
  33. d.key = item.value;
  34. d.keyLabel = item.label;
  35. d.keyPopupVisible = false;
  36. "
  37. >
  38. {{ item.label }}
  39. </li>
  40. </ul>
  41. </template>
  42. </t-select-input>
  43. <t-input v-else class="input-key" v-model="d.key" />
  44. <t-input class="input-value" v-model="d.value" />
  45. <div class="flex operation">
  46. <add-circle-icon class="hover ml-4" @click="addData(i)" />
  47. <minus-circle-icon class="hover ml-4" @click="delData(i)" />
  48. </div>
  49. </div>
  50. </div>
  51. </t-tab-panel>
  52. <t-tab-panel :value="2" :label="$t('JSON模式')">
  53. <template #label>
  54. {{$t('JSON模式')}}
  55. <t-tooltip v-if="props.tips" :content="props.tips" placement="top">
  56. <HelpCircleIcon class="ml-4" />
  57. </t-tooltip>
  58. </template>
  59. <CodeEditor
  60. :key="codeUpdateKey"
  61. :json="true"
  62. :language="'json'"
  63. v-model="json"
  64. style="height: 300px"
  65. />
  66. </t-tab-panel>
  67. </t-tabs>
  68. </t-dialog>
  69. </template>
  70. <script lang="ts" setup>
  71. import { ref, toRaw, onMounted, watch } from 'vue';
  72. import CodeEditor from '@/views/components/common/CodeEditor.vue';
  73. import {
  74. AddCircleIcon,
  75. MinusCircleIcon,
  76. HelpCircleIcon,
  77. } from 'tdesign-icons-vue-next';
  78. import { s8 } from '@/services/random';
  79. const props = defineProps<{
  80. visible: boolean;
  81. data: any;
  82. options?: any[];
  83. tips?: string;
  84. }>();
  85. const emit = defineEmits(['update:visible', 'change']);
  86. const activedProp = ref([]);
  87. const simpleData = ref([]);
  88. const json = ref({});
  89. const codeUpdateKey = ref(s8());
  90. watch(
  91. () => props.visible,
  92. () => {
  93. if (!props.data) {
  94. json.value = {};
  95. simpleData.value = [{ key: '', value: '' }];
  96. }
  97. json.value = JSON.parse(JSON.stringify(props.data));
  98. if (json.value && !Array.isArray(json.value)) {
  99. simpleData.value = objToArr(json.value);
  100. }
  101. if (!simpleData.value?.length) {
  102. simpleData.value = [{ key: '', value: '' }];
  103. }
  104. if (tabValue.value === 2) {
  105. codeUpdateKey.value = s8();
  106. }
  107. }
  108. );
  109. const tabChange = (val) => {
  110. if (val === 1) {
  111. simpleData.value = objToArr(json.value);
  112. if (!simpleData.value?.length) {
  113. simpleData.value.push({ key: '', value: '' });
  114. }
  115. } else if (val === 2) {
  116. json.value = arrToObj(simpleData.value);
  117. }
  118. };
  119. const addData = (index) => {
  120. simpleData.value.splice(index + 1, 0, { key: '', value: '' });
  121. };
  122. const delData = (index) => {
  123. if (index === 0) {
  124. simpleData.value[0].key = '';
  125. simpleData.value[0].value = '';
  126. } else {
  127. simpleData.value.splice(index, 1);
  128. }
  129. };
  130. function close() {
  131. emit('update:visible', false);
  132. }
  133. const tabValue = ref(1);
  134. const arrToObj = (arr) => {
  135. return arr.reduce((accumulator, current) => {
  136. if (current.key) {
  137. accumulator[current.key] = current.value;
  138. }
  139. return accumulator;
  140. }, {});
  141. };
  142. const objToArr = (obj) => {
  143. return Object.entries(obj).map(([key, value]) => ({
  144. key: key,
  145. value: value,
  146. label: key,
  147. keyLabel: key,
  148. }));
  149. };
  150. const confirm = () => {
  151. if (tabValue.value === 1) {
  152. json.value = arrToObj(simpleData.value);
  153. }
  154. emit('change', json.value);
  155. };
  156. const onKeyInput = (item: any) => {
  157. item.keyLabel = item.key;
  158. };
  159. </script>
  160. <style lang="postcss" scoped>
  161. .t-tab-panel {
  162. height: 300px;
  163. overflow-y: hidden;
  164. }
  165. :deep(.t-input) {
  166. border-color: transparent;
  167. &:hover {
  168. border-color: var(--color-primary);
  169. }
  170. }
  171. .input-key {
  172. width: 140px;
  173. :deep(.t-input) {
  174. width: 140px;
  175. }
  176. }
  177. .one-data {
  178. .operation {
  179. display: none;
  180. justify-content: center;
  181. align-items: center;
  182. color: var(--td-text-color-secondary);
  183. }
  184. &:hover {
  185. .operation {
  186. display: flex;
  187. height: 30px;
  188. }
  189. }
  190. }
  191. </style>