chargesForm.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. <template>
  2. <div>
  3. <el-form :model="form"
  4. label-suffix=": "
  5. ref="form">
  6. <el-form-item label="所属分部"
  7. prop="organId"
  8. :rules="[{required: true, message: '请选择所属分部', trigger: 'change'}]"
  9. :label-width="formLabelWidth">
  10. <el-select v-model.trim="form.organId"
  11. clearable
  12. placeholder="请选择所属分部"
  13. filterable>
  14. <el-option v-for="(item, index) in branchList"
  15. :key="index"
  16. :label="item.label"
  17. :value="item.value">
  18. </el-option>
  19. </el-select>
  20. </el-form-item>
  21. <el-form-item label="乐团模式"
  22. prop="chargeTypeId"
  23. :rules="[{required: true, message: '请选择乐团模式', trigger: 'change'}]"
  24. :label-width="formLabelWidth">
  25. <el-select v-model.trim="form.chargeTypeId"
  26. clearable
  27. placeholder="请选择乐团模式"
  28. filterable>
  29. <el-option v-for="(item, index) in typesList"
  30. :key="index"
  31. :label="item.label"
  32. :value="item.value">
  33. </el-option>
  34. </el-select>
  35. </el-form-item>
  36. <el-form-item label="收费方式名称"
  37. prop="name"
  38. :rules="[{required: true, message: '请输入收费方式名称', trigger: 'blur'}]"
  39. :label-width="formLabelWidth">
  40. <el-input v-model.trim="form.name"
  41. placeholder="请输入收费方式名称"
  42. clearable>
  43. </el-input>
  44. </el-form-item>
  45. <div class="class-items">
  46. <div class="items">
  47. <div class="items-header">
  48. <span class="name">课程类型</span>
  49. <span class="name">是否可选</span>
  50. <span class="name">课程总时长(分钟)</span>
  51. <span class="name">现价(元)</span>
  52. <span class="name">原价(元)</span>
  53. <span class="ctrl"></span>
  54. </div>
  55. <div class="item" v-for="(item, index) in form.details" :key="index">
  56. <el-form-item
  57. :prop="`details.${index}.courseType`"
  58. :rules="[{required: true, message: '请选择课程类型', trigger: 'change'}]"
  59. >
  60. <el-select v-model.trim="item.courseType"
  61. size="mini"
  62. clearable
  63. @change="() => courseItemChange(item, index)"
  64. filterable>
  65. <el-option v-for="item in courseTypes"
  66. :key="item.courseType"
  67. :label="courseType[item.courseType]"
  68. :disabled="isOptionDisabled(item.courseType)"
  69. :value="item.courseType">
  70. </el-option>
  71. </el-select>
  72. </el-form-item>
  73. <el-form-item
  74. :prop="`details.${index}.isStudentOptional`"
  75. :rules="[{required: true, message: '请选择是否可选', trigger: 'change'}]"
  76. >
  77. <el-select v-model.trim="item.isStudentOptional"
  78. size="mini"
  79. clearable
  80. filterable>
  81. <el-option v-for="item in boolOptions"
  82. :key="item.label"
  83. :label="item.label"
  84. :value="item.value">
  85. </el-option>
  86. </el-select>
  87. </el-form-item>
  88. <el-form-item
  89. :prop="`details.${index}.courseTotalMinuties`"
  90. :rules="[{required: true, message: '请输入课程总时长', trigger: 'blur'}]"
  91. >
  92. <el-input-number
  93. size="mini"
  94. style="width: 90%!important;"
  95. class="number-input"
  96. v-model="item.courseTotalMinuties"
  97. :controls="false"
  98. :precision="0"
  99. :min="1"
  100. @change="() => courseItemChange(item, index)"
  101. placeholder="课程总时长"
  102. />
  103. </el-form-item>
  104. <el-form-item
  105. :prop="`details.${index}.courseCurrentPrice`"
  106. :rules="[{required: true, message: '请输入课程现价', trigger: 'blur'}]"
  107. >
  108. <el-input-number
  109. size="mini"
  110. style="width: 90%!important;"
  111. class="number-input"
  112. v-model="item.courseCurrentPrice"
  113. :controls="false"
  114. :precision="0"
  115. :min="1"
  116. placeholder="课程现价"
  117. />
  118. </el-form-item>
  119. <el-form-item
  120. :prop="`details.${index}.courseOriginalPrice`"
  121. :rules="[{required: true, message: '请输入课程原价', trigger: 'blur'}]"
  122. >
  123. <el-input-number
  124. size="mini"
  125. style="width: 90%!important;"
  126. class="number-input"
  127. v-model="item.courseOriginalPrice"
  128. :controls="false"
  129. :precision="0"
  130. :min="1"
  131. placeholder="课程原价"
  132. />
  133. </el-form-item>
  134. <span class="ctrl">
  135. <i @click="removeItem(index)" v-if="form.details.length > 1" class="el-icon-circle-close" />
  136. </span>
  137. </div>
  138. </div>
  139. <el-button
  140. icon="el-icon-circle-plus-outline"
  141. plain class="create-type-button"
  142. type="info"
  143. size="small"
  144. @click="addItem"
  145. >新增课程类型</el-button>
  146. </div>
  147. <el-row>
  148. <el-col :span="6">
  149. <el-form-item label="原价"
  150. prop="totalOriginalPrice"
  151. label-width="50px">
  152. {{ totalOriginalPrice | moneyFormat}}
  153. </el-form-item>
  154. </el-col>
  155. <el-col :span="6">
  156. <el-form-item label="现价"
  157. prop="totalCurrentPrice"
  158. label-width="50px">
  159. {{ totalCurrentPrice | moneyFormat}}
  160. </el-form-item>
  161. </el-col>
  162. </el-row>
  163. </el-form>
  164. <span slot="footer"
  165. class="dialog-footer">
  166. <el-button @click="$listeners.close">取 消</el-button>
  167. <el-button @click="submit"
  168. type="primary">确 定</el-button>
  169. </span>
  170. </div>
  171. </template>
  172. <script>
  173. const initItem = {
  174. courseType: '',
  175. isStudentOptional: '',
  176. courseTotalMinuties: '',
  177. courseOriginalPrice: '',
  178. courseCurrentPrice: '',
  179. }
  180. import {
  181. musicGroupOrganizationCourseSettingsAdd,
  182. musicGroupOrganizationCourseSettingsUpdate,
  183. getOrganizationCourseUnitPriceSettings
  184. } from '@/api/specialSetting'
  185. import { classTimeList } from '@/utils/searchArray'
  186. import { courseType, boolOptions } from '@/constant'
  187. import { objectToOptions } from '@/utils'
  188. import numeral from 'numeral'
  189. const plusNum = (items = [], key) => {
  190. let money = 0
  191. const _items = items.filter(item => !item.isStudentOptional)
  192. for (const item of _items) {
  193. money += parseFloat(parseFloat(item[key] || 0).toFixed(2) || 0)
  194. }
  195. return money
  196. }
  197. const initForm = {
  198. organId: '',
  199. classTimeList: '',
  200. chargeTypeId: '',
  201. name: '',
  202. details: [{}],
  203. }
  204. export default {
  205. name: 'modal-chargesForm',
  206. props: ['branchList', 'typesList', 'rowDetail'],
  207. data() {
  208. return {
  209. form: {...initForm},
  210. formLabelWidth: '120px',
  211. courseType,
  212. courseTypeOptions: objectToOptions(courseType),
  213. boolOptions: objectToOptions(boolOptions),
  214. courseTypes: [],
  215. courseTypesByType: {},
  216. }
  217. },
  218. computed: {
  219. totalOriginalPrice() {
  220. return plusNum(this.form.details, 'courseOriginalPrice')
  221. },
  222. totalCurrentPrice() {
  223. return plusNum(this.form.details, 'courseCurrentPrice')
  224. }
  225. },
  226. watch: {
  227. rowDetail() {
  228. this.updateForm()
  229. },
  230. async 'form.chargeTypeId'() {
  231. try {
  232. const res = await getOrganizationCourseUnitPriceSettings({
  233. chargeTypeId: this.form.chargeTypeId,
  234. rows: 9999
  235. })
  236. const d = {}
  237. this.courseTypes = res.data.rows
  238. for (const item of this.courseTypes) {
  239. d[item.courseType] = item
  240. }
  241. this.courseTypesByType = d
  242. } catch (error) {}
  243. }
  244. },
  245. mounted() {
  246. this.updateForm()
  247. },
  248. methods: {
  249. courseItemChange(item, index) {
  250. if (item.courseType) {
  251. const active = this.courseTypesByType[item.courseType] || {}
  252. const _list = this.form.details
  253. _list[index] = {
  254. ...item,
  255. courseCurrentPrice: Math.ceil(active.unitPrice * (item.courseTotalMinuties || 1)),
  256. courseOriginalPrice: Math.ceil(active.unitPrice * (item.courseTotalMinuties || 1))
  257. }
  258. this.$set(this.form, `details`, [..._list])
  259. }
  260. },
  261. updateForm() {
  262. if (this.rowDetail) {
  263. const { organId, classTimeList, chargeTypeId, name, details } = this.rowDetail
  264. this.form = {
  265. organId,
  266. classTimeList,
  267. chargeTypeId,
  268. name,
  269. details: details.map(item => ({
  270. ...item,
  271. isStudentOptional: String(item.isStudentOptional)
  272. }))
  273. }
  274. } else {
  275. this.form = {...initForm}
  276. }
  277. },
  278. isOptionDisabled(key) {
  279. const selected = this.form.details.map(item => item.courseType)
  280. return selected.includes(key)
  281. },
  282. addItem() {
  283. const _items = [...this.form.details, {}]
  284. this.form.details = _items
  285. },
  286. removeItem(index) {
  287. const _items = [...this.form.details]
  288. _items[index] = null
  289. this.form.details = _items.filter(item => !!item)
  290. },
  291. submit() {
  292. this.$refs.form.validate(async (valid) => {
  293. if (valid) {
  294. try {
  295. if (this.rowDetail) {
  296. const res = await musicGroupOrganizationCourseSettingsUpdate({
  297. id: this.rowDetail.id,
  298. ...this.form
  299. })
  300. this.$message.success('更新成功')
  301. } else {
  302. const res = await musicGroupOrganizationCourseSettingsAdd(this.form)
  303. this.$message.success('提交成功')
  304. }
  305. this.$listeners.close()
  306. this.$listeners.submited()
  307. } catch (error) {}
  308. }
  309. })
  310. }
  311. },
  312. }
  313. </script>
  314. <style lang="less" scoped>
  315. .dialog-footer{
  316. display: block;
  317. text-align: right;
  318. }
  319. .items{
  320. .items-header,
  321. .item{
  322. display: flex;
  323. >.el-form-item,
  324. >span{
  325. width: 100%;
  326. text-align: center;
  327. padding: 0 10px;
  328. &.ctrl{
  329. width: 300px;
  330. }
  331. }
  332. }
  333. .items-header{
  334. background-color: #f1f1f1;
  335. padding: 10px 0;
  336. margin-bottom: 10px;
  337. >span{
  338. line-height: 26px;
  339. }
  340. }
  341. }
  342. .create-type-button{
  343. width: 100%;
  344. margin-bottom: 20px;
  345. }
  346. .ctrl{
  347. display: flex;
  348. align-items: center;
  349. justify-content: center;
  350. margin-bottom: 26px;
  351. i{
  352. cursor: pointer;
  353. font-size: 18px;
  354. }
  355. }
  356. </style>