index.vue 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. <template>
  2. <div class="main animate__animated animate__backInRight" v-loading="loading">
  3. <custom-search-bar :fields="fields.filter((f) => f.isSearch)" v-model="searchForm" @search="search" @reset="toReset">
  4. <template #field>
  5. <el-option v-for="i in fieldList" :key="i._id" :label="i.label" :value="i.value"></el-option>
  6. </template>
  7. <template #urgent>
  8. <el-option v-for="i in urgentList" :key="i._id" :label="i.label" :value="i.value"></el-option>
  9. </template>
  10. <template #method>
  11. <el-option v-for="i in methodList" :key="i._id" :label="i.label" :value="i.value"></el-option>
  12. </template>
  13. </custom-search-bar>
  14. <custom-button-bar :fields="buttonFields" @add="toAdd"></custom-button-bar>
  15. <custom-table :data="data" :fields="fields" @query="search" :total="total" :opera="opera" @exam="toExam" @edit="toEdit" @delete="toDelete">
  16. <template #is_use="{ row }">
  17. <el-tag v-if="row.is_use == '0'" type="success" @click="toUse(row, '1')">启用</el-tag>
  18. <el-tag v-else type="info" @click="toUse(row, '0')">禁用</el-tag>
  19. </template>
  20. </custom-table>
  21. <el-dialog v-model="dialog.show" :title="dialog.title" :destroy-on-close="false" @close="toClose">
  22. <el-row>
  23. <el-col :span="24" v-if="dialog.type == '1'">
  24. <custom-form v-model="form" :fields="formFields" :rules="rules" @save="toSave">
  25. <template #is_use>
  26. <el-radio v-for="i in isUseList" :key="i._id" :label="i.value">{{ i.label }}</el-radio>
  27. </template>
  28. <template #field>
  29. <el-option v-for="i in fieldList" :key="i._id" :label="i.label" :value="i.value"></el-option>
  30. </template>
  31. <template #urgent>
  32. <el-option v-for="i in urgentList" :key="i._id" :label="i.label" :value="i.value"></el-option>
  33. </template>
  34. <template #method>
  35. <el-option v-for="i in methodList" :key="i._id" :label="i.label" :value="i.value"></el-option>
  36. </template>
  37. <template #area>
  38. <el-cascader v-model="form.area" :props="{ value: 'label', label: 'label' }" :options="cityList" style="width: 100%" />
  39. </template>
  40. </custom-form>
  41. </el-col>
  42. <el-col :span="24" v-if="dialog.type == '2'">
  43. <custom-form v-model="examForm" :fields="examFormFields" :rules="examRules" @save="toExamSave">
  44. <template #status>
  45. <el-option v-for="i in statusList" :key="i._id" :label="i.label" :value="i.value"></el-option>
  46. </template>
  47. </custom-form>
  48. </el-col>
  49. </el-row>
  50. </el-dialog>
  51. </div>
  52. </template>
  53. <script setup>
  54. // API 引用
  55. import { getCity } from '@/utils/city'
  56. import { cloneDeep, get } from 'lodash-es'
  57. const $checkRes = inject('$checkRes')
  58. const { t } = useI18n()
  59. // 接口
  60. import { SupplyStore } from '@/store/api/platform/supply'
  61. import { DictDataStore } from '@/store/api/system/dictData'
  62. const store = SupplyStore()
  63. const dictDataStore = DictDataStore()
  64. const data = ref([])
  65. const searchForm = ref({})
  66. const fields = [
  67. { label: t('pages.demand.name'), model: 'name', isSearch: true },
  68. { label: t('pages.demand.field'), model: 'field', isSearch: true, type: 'select', format: (i) => getDict(i, 'field') },
  69. { label: t('pages.demand.urgent'), model: 'urgent', isSearch: true, type: 'select', format: (i) => getDict(i, 'urgent') },
  70. { label: t('pages.demand.method'), model: 'method', isSearch: true, type: 'select', format: (i) => getDict(i, 'method') },
  71. { label: t('pages.demand.money'), model: 'money' },
  72. { label: t('pages.demand.is_use'), model: 'is_use', custom: true, format: (i) => getDict(i, 'is_use') },
  73. { label: t('pages.demand.demand_status'), model: 'demand_status', format: (i) => getDict(i, 'demand') },
  74. { label: t('pages.demand.status'), model: 'status', format: (i) => getDict(i, 'status') }
  75. ]
  76. const opera = [
  77. { label: t('common.update'), method: 'edit' },
  78. { label: t('common.exam'), method: 'exam', type: 'warning', display: (i) => i.status === '0' },
  79. { label: t('common.delete'), method: 'delete', confirm: true, type: 'danger', display: (i) => i.is_use === '1' }
  80. ]
  81. const buttonFields = [{ label: t('common.create'), method: 'add' }]
  82. let skip = 0
  83. let limit = inject('limit')
  84. const total = ref(0)
  85. // 字典表
  86. const isUseList = ref([])
  87. const statusList = ref([])
  88. const methodList = ref([])
  89. const urgentList = ref([])
  90. const fieldList = ref([])
  91. const cityList = ref([])
  92. const demandList = ref([])
  93. // 加载中
  94. const loading = ref(false)
  95. const formFields = ref([
  96. { label: t('pages.demand.name'), model: 'name' },
  97. { label: t('pages.demand.field'), model: 'field', type: 'select' },
  98. { label: t('pages.demand.urgent'), model: 'urgent', type: 'select' },
  99. { label: t('pages.demand.method'), model: 'method', type: 'select' },
  100. { label: t('pages.demand.money'), model: 'money' },
  101. { label: t('pages.demand.area'), model: 'area', custom: true },
  102. { label: t('pages.demand.time'), model: 'time', type: 'daterange' },
  103. { label: t('pages.demand.is_use'), model: 'is_use', type: 'radio' },
  104. { label: t('pages.demand.brief'), model: 'brief', type: 'textarea' }
  105. ])
  106. const rules = reactive({ name: [{ required: true, message: t('pages.demand.titleMessage'), trigger: 'blur' }] })
  107. const dialog = ref({ type: '1', show: false, title: t('pages.demand.addDialogTitle') })
  108. const form = ref({})
  109. // 审核
  110. const examFormFields = [{ label: t('pages.demand.status'), model: 'status', type: 'select' }]
  111. const examRules = reactive({ status: [{ required: true, message: t('common.statusMessage'), trigger: 'blur' }] })
  112. const examForm = ref({})
  113. // 请求
  114. onMounted(async () => {
  115. loading.value = true
  116. getCity().then((response) => {
  117. cityList.value = response.address
  118. })
  119. await searchOther()
  120. await search({ skip, limit })
  121. loading.value = false
  122. })
  123. const searchOther = async () => {
  124. let result
  125. // 是否使用
  126. result = await dictDataStore.query({ code: 'isUse', is_use: '0' })
  127. if ($checkRes(result)) isUseList.value = result.data
  128. // 状态
  129. result = await dictDataStore.query({ code: 'examStatus', is_use: '0' })
  130. if ($checkRes(result)) statusList.value = result.data
  131. // 合作方式
  132. result = await dictDataStore.query({ code: 'method', is_use: '0' })
  133. if ($checkRes(result)) methodList.value = result.data
  134. // 需求紧急度
  135. result = await dictDataStore.query({ code: 'urgent', is_use: '0' })
  136. if ($checkRes(result)) urgentList.value = result.data
  137. // 技术领域
  138. result = await dictDataStore.query({ code: 'field', is_use: '0' })
  139. if ($checkRes(result)) fieldList.value = result.data
  140. // 需求状态
  141. result = await dictDataStore.query({ code: 'demandStatus', is_use: '0' })
  142. if ($checkRes(result)) demandList.value = result.data
  143. }
  144. const search = async (query = { skip: 0, limit }) => {
  145. const info = { skip: query.skip, limit: query.limit, ...searchForm.value, type: '0' }
  146. const res = await store.query(info)
  147. if (res.errcode == '0') {
  148. data.value = res.data
  149. total.value = res.total
  150. }
  151. }
  152. // 字典数据转换
  153. const getDict = (data, model) => {
  154. let res
  155. if (model == 'is_use') res = isUseList.value.find((f) => f.value == data)
  156. else if (model == 'status') res = statusList.value.find((f) => f.value == data)
  157. else if (model == 'method') res = methodList.value.find((f) => f.value == data)
  158. else if (model == 'urgent') res = urgentList.value.find((f) => f.value == data)
  159. else if (model == 'field') res = fieldList.value.find((f) => f.value == data)
  160. else if (model == 'demand') res = demandList.value.find((f) => f.value == data)
  161. return get(res, 'label')
  162. }
  163. // 添加
  164. const toAdd = () => {
  165. form.value = { type: '0' }
  166. dialog.value = { type: '1', show: true, title: t('pages.demand.addDialogTitle') }
  167. }
  168. // 修改
  169. const toEdit = (data) => {
  170. form.value = data
  171. dialog.value = { type: '1', show: true, title: t('pages.demand.upDialogTitle') }
  172. }
  173. // 删除
  174. const toDelete = async (data) => {
  175. const res = await store.del(data._id)
  176. if ($checkRes(res, true)) {
  177. search({ skip: 0, limit })
  178. }
  179. }
  180. const toSave = async () => {
  181. const data = cloneDeep(form.value)
  182. const other = { status: '0' }
  183. let res
  184. if (get(data, '_id')) res = await store.update({ ...data, ...other })
  185. else res = await store.create({ ...data, ...other })
  186. if ($checkRes(res, true)) {
  187. search({ skip: 0, limit })
  188. toClose()
  189. }
  190. }
  191. // 审核
  192. const toExam = (data) => {
  193. examForm.value = data
  194. dialog.value = { type: '2', show: true, title: t('pages.demand.examDialogTitle') }
  195. }
  196. // 审核保存
  197. const toExamSave = async () => {
  198. const data = cloneDeep(examForm.value)
  199. let res = await store.update(data)
  200. if ($checkRes(res, true)) {
  201. search({ skip: 0, limit })
  202. toClose()
  203. }
  204. }
  205. // 开启或禁用
  206. const toUse = async (data, is_use) => {
  207. ElMessageBox.confirm(`确定修改【${data.name}】数据?`, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
  208. .then(async () => {
  209. let res = await store.update({ _id: get(data, '_id'), is_use })
  210. if ($checkRes(res, true)) {
  211. search({ skip: 0, limit })
  212. }
  213. })
  214. .catch(() => {})
  215. }
  216. // 重置
  217. const toReset = async () => {
  218. searchForm.value = {}
  219. await search({ skip, limit })
  220. }
  221. const toClose = () => {
  222. form.value = {}
  223. dialog.value = { show: false }
  224. }
  225. </script>
  226. <style scoped lang="scss"></style>