index.vue 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. <template>
  2. <el-dialog :title="title" v-model="open" width="700px" append-to-body>
  3. <el-form ref="dialogFormRef" :model="form" :label-width="labelWidth" class="dialogClass">
  4. <template v-for="item in column" :key="item.prop">
  5. <!-- 输入框 -->
  6. <el-form-item :label="item.label" v-if="item.type === 'input'" :prop="item.prop" :rules="item.rules">
  7. <el-input v-model="form[item.prop]" :placeholder="'请输入' + item.label" clearable
  8. :disabled="disables[item.prop]">
  9. <template v-if="item.dese" #append> <a @click="item.deseClick ? item.deseClick(form) : ''">{{
  10. item.dese }}</a> </template>
  11. </el-input>
  12. </el-form-item>
  13. <!-- 文本域 -->
  14. <el-form-item :label="item.label" v-if="item.type === 'textarea' && (item.show ? item.show(form) : true)"
  15. :prop="item.prop" :rules="item.rules">
  16. <el-input v-model="form[item.prop]" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }"
  17. :placeholder="'请输入' + item.label" clearable :disabled="disables[item.prop]" />
  18. </el-form-item>
  19. <el-form-item :label="item.label" v-if="item.type === 'radio' && item.options"
  20. :prop="item.prop"
  21. :rules="item.rules">
  22. <el-radio-group v-model="form[item.prop]" :disabled="disables[item.prop]">
  23. <el-radio v-for="dict in item.options" :key="dict.value" :value="dict.value">{{ dict.label
  24. }}</el-radio>
  25. </el-radio-group>
  26. </el-form-item>
  27. <!-- 时间选择 -->
  28. <el-form-item :label="item.label" v-if="item.type === 'date'" :prop="item.prop" :rules="item.rules">
  29. <el-date-picker v-model="form[item.prop]" value-format="YYYY-MM-DD" type="daterange"
  30. range-separator="-" start-placeholder="开始日期" clearable end-placeholder="结束日期"
  31. :disabled="disables[item.prop]"></el-date-picker>
  32. </el-form-item>
  33. <el-form-item :label="item.label" v-if="item.type === 'picker'" :prop="item.prop" :rules="item.rules">
  34. <el-date-picker v-model="form[item.prop]" type="datetime"
  35. :disabled="disables[item.prop]"></el-date-picker>
  36. </el-form-item>
  37. <!-- 下拉框选择 -->
  38. <el-form-item :label="item.label" v-if="item.type === 'select' && item.dictionary" :prop="item.prop"
  39. :rules="item.rules">
  40. <el-select v-model="form[item.prop]" :placeholder="'请选择' + item.label" clearable
  41. :disabled="disables[item.prop]">
  42. <el-option v-for="dict in dictionaryOptions[item.dictionary]" :key="dict.value"
  43. :label="dict.label" :value="dict.value"></el-option>
  44. </el-select>
  45. </el-form-item>
  46. <el-form-item :label="item.label" v-if="item.type === 'select' && item.options" :prop="item.prop"
  47. :rules="item.rules">
  48. <el-select v-model="form[item.prop]" :placeholder="'请选择' + item.label" clearable
  49. :disabled="disables[item.prop]">
  50. <el-option v-for="dict in item.options" :key="dict.value" :label="dict.label"
  51. :value="dict.value"></el-option>
  52. </el-select>
  53. </el-form-item>
  54. <!-- 联动选择框 -->
  55. <el-form-item :label="item.label" v-if="item.type === 'cascader'" :prop="item.prop">
  56. <el-cascader v-model="form[item.prop]" :options="item.options || []" style="width: 100%;"
  57. :props="item.props" :disabled="disables[item.prop]" />
  58. </el-form-item>
  59. <!-- 图片预览 -->
  60. <el-form-item :label="item.label" v-if="item.type === 'img'" :prop="item.prop">
  61. <el-space wrap>
  62. <div v-for="(imgItem, imgIndex) in getImages(item.prop)" :key="imgIndex">
  63. <!-- <img :src="imgItem" alt="" srcset="" style="width: 100px;" /> -->
  64. <el-image
  65. style="width: 100px;"
  66. :src="imgItem"
  67. :zoom-rate="1.2"
  68. :max-scale="7"
  69. :min-scale="0.2"
  70. :preview-src-list="getImages(item.prop)"
  71. show-progress
  72. :initial-index="4"
  73. fit="cover"
  74. />
  75. </div>
  76. </el-space>
  77. </el-form-item>
  78. <!-- 文本显示 -->
  79. <el-form-item :label="item.label" v-if="item.type === 'text'" :prop="item.prop" :rules="item.rules">
  80. {{ form[item.prop] }} <a v-if="item.dese" @click="item.deseClick ? item.deseClick(form) : ''">{{
  81. item.dese }}</a>
  82. </el-form-item>
  83. <!-- 字典显示 -->
  84. <el-form-item :label="item.label" v-if="item.type === 'dict'" :prop="item.prop" :rules="item.rules">
  85. <dict-tag v-if="item.dict" :options="item.dict" :value="String(form[item.prop])" />
  86. </el-form-item>
  87. </template>
  88. </el-form>
  89. <template #footer>
  90. <div class="dialog-footer">
  91. <el-button type="primary" @click="submitForm">确 定</el-button>
  92. <el-button @click="cancel">取 消</el-button>
  93. </div>
  94. </template>
  95. </el-dialog>
  96. </template>
  97. <script setup>
  98. import { toRaw } from 'vue';
  99. import { computed, reactive } from 'vue';
  100. const { proxy } = getCurrentInstance();
  101. const props = defineProps({
  102. title: {
  103. type: String,
  104. default: '新增',
  105. },
  106. column: {
  107. type: Object,
  108. default: [],
  109. required: true
  110. },
  111. labelWidth: {
  112. type: String,
  113. default: '120px',
  114. },
  115. })
  116. const open = ref(false);
  117. const form = ref({});
  118. const dictionaryOptions = reactive({})
  119. const emit = defineEmits(['submit']);
  120. const dialogFormRef = ref(null);
  121. const disables = ref({});
  122. const formStatus = ref('form') //form:表单 details:详情
  123. const getImages = (key) => {
  124. if(typeof key === 'object'){
  125. return key.map(item =>{
  126. return form.value[item]
  127. })
  128. }
  129. const imgs = form.value[key];
  130. if (!imgs) {
  131. return [];
  132. }
  133. return imgs.split(',')
  134. }
  135. const handleInit = () => {
  136. try {
  137. const data = props.column.value || props.column;
  138. const keys = data.map(item => {
  139. if (item.type === 'select' && item.dictionary) {
  140. return item.dictionary;
  141. }
  142. }).filter(Boolean);
  143. if (keys && keys.length > 0) {
  144. const res = proxy.useDict(keys);
  145. Object.assign(dictionaryOptions, res)
  146. }
  147. } catch (error) {
  148. console.log('error', error);
  149. }
  150. }
  151. onMounted(() => {
  152. handleInit();
  153. })
  154. const handleDialog = (status, data) => {
  155. console.log('status', status);
  156. if (data) {
  157. form.value = data;
  158. }
  159. open.value = status;
  160. }
  161. const submitForm = () => {
  162. proxy.$refs["dialogFormRef"].validate(valid => {
  163. if (valid) {
  164. console.log('form', form.value);
  165. emit('submit', form.value)
  166. }
  167. });
  168. }
  169. const cancel = () => {
  170. open.value = false;
  171. disables.value = {};
  172. dialogFormRef.value.resetFields();
  173. console.log('cancel');
  174. }
  175. const initForm = (data, disableData,formStatus) => {
  176. console.log('initForm', data);
  177. form.value = data;
  178. if (disableData) {
  179. disables.value = disableData;
  180. }
  181. }
  182. defineExpose({
  183. handleDialog,
  184. initForm,
  185. })
  186. </script>
  187. <style lang='scss' scoped>
  188. .dialogClass {
  189. height: calc(100vh - 280px);
  190. overflow: hidden;
  191. overflow-y: auto;
  192. }
  193. </style>