addMaterial.tsx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. import {
  2. FormInst,
  3. FormItemRule,
  4. FormRules,
  5. NButton,
  6. NCascader,
  7. NDrawer,
  8. NDrawerContent,
  9. NForm,
  10. NFormItem,
  11. NInput,
  12. NInputGroup,
  13. NRadio,
  14. NRadioGroup,
  15. NSelect,
  16. NSpace,
  17. NSpin,
  18. NSwitch,
  19. useMessage
  20. } from 'naive-ui'
  21. import { defineComponent, inject, onMounted, reactive, ref, watch } from 'vue'
  22. import { fetchMaterailDetail, materialSave, updateMaterailData } from '../api'
  23. import { materialType } from '../educationalData'
  24. import UploadFile from '@/components/upload-file'
  25. import { lessonType } from '@/views/knowledge-manage/knowledgeTypeData'
  26. import SelectMusicSheet from './selectMusicSheet'
  27. import Editor from '@/components/editor'
  28. export default defineComponent({
  29. name: 'addMaterial',
  30. emits: ['handleSuccess', 'close'],
  31. props: ['item', 'isLook', 'categoryList'],
  32. setup(props, { emit }) {
  33. const message = useMessage()
  34. const loading = ref(false)
  35. const formRef = ref<FormInst | null>(null)
  36. const formContentRef = ref<any>()
  37. const saveModel = reactive({
  38. name: '',
  39. sn: '', //序号
  40. materialCategoryId: null, //素材分类
  41. // adviseStudyTimeSecond: null,
  42. type: materialType.视频,
  43. phaseGoals: null,
  44. checkItem: null,
  45. materialRefs: [] as any,
  46. content: '', // 视频、图片链接或者是曲目编号
  47. courseTypeCode: [], // 课程类型
  48. enableFlag: true //启用状态
  49. })
  50. onMounted(async () => {
  51. if (props?.item?.id) {
  52. loading.value = true
  53. const res: any = await fetchMaterailDetail(props.item.id)
  54. if (res?.code == 200) {
  55. Object.keys(saveModel).forEach((key: any) => {
  56. if (res?.data?.[key]) {
  57. if (key === 'adviseStudyTimeSecond') (saveModel as any)[key] = res.data[key] + ''
  58. else if (key === 'courseTypeCode')
  59. (saveModel as any)[key] = res.data[key]?.split(',') || []
  60. else (saveModel as any)[key] = res.data[key]
  61. }
  62. if (key === 'enableFlag') (saveModel as any)[key] = res.data[key]
  63. })
  64. if (saveModel.type === 'SONG') {
  65. musicOpentions.music = {
  66. name: res.data.contentDesc
  67. }
  68. }
  69. // else {
  70. // if (res.data.materialRefs && res.data.materialRefs.length > 0) {
  71. // res.data.materialRefs.forEach((row: any) => {
  72. // saveModel.materialRefs.push({
  73. // resourceId: row.resourceId,
  74. // knowledgeType: row.knowledgeType,
  75. // resourceName: row.resourceName
  76. // })
  77. // })
  78. // }
  79. // }
  80. console.log('🚀 ~ saveModel', saveModel)
  81. }
  82. loading.value = false
  83. }
  84. })
  85. function validateContent(rule: FormItemRule, value: string) {
  86. if (!value) {
  87. return saveModel.type === materialType.视频
  88. ? new Error('请上传视频')
  89. : saveModel.type === materialType.图片
  90. ? new Error('请上传图片')
  91. : new Error('请选择曲目')
  92. }
  93. return true
  94. }
  95. function validateAdviseStudyTimeSecond(rule: FormItemRule, value: string) {
  96. if (!value) {
  97. return new Error('请填写时间')
  98. }
  99. if (!/^\+?[1-9]\d*$/.test(value)) {
  100. return new Error('请填写正确的时间')
  101. }
  102. return true
  103. }
  104. function validateCourseTypeCode(rule: FormItemRule, value: []) {
  105. if (Array.isArray(value) && !value.length) {
  106. return new Error('请选择课程类型')
  107. }
  108. return true
  109. }
  110. const rules: FormRules = {
  111. name: [{ required: true, message: '请填写素材名称', trigger: ['blur', 'change'] }],
  112. sn: [{ required: true, message: '分段编号', trigger: ['blur', 'change'] }],
  113. materialCategoryId: [
  114. { required: true, message: '请选择素材分类', trigger: ['blur', 'change'] }
  115. ],
  116. adviseStudyTimeSecond: [
  117. {
  118. validator: validateAdviseStudyTimeSecond,
  119. trigger: ['change']
  120. }
  121. ],
  122. content: [{ validator: validateContent, trigger: ['blur', 'change', 'input'] }],
  123. courseTypeCode: [
  124. {
  125. validator: validateCourseTypeCode,
  126. message: '请选择课程类型',
  127. trigger: ['blur', 'change']
  128. }
  129. ],
  130. phaseGoals: [{
  131. required: true, message: '请填写阶段目标' , trigger: ['blur', 'change', 'input']
  132. }],
  133. checkItem: [{
  134. required: true, message: '请填写检查事项', trigger: ['blur', 'change', 'input']
  135. }]
  136. }
  137. // const categoryList = inject('categoryList', { list: [] }).list || []
  138. const submit = () => {
  139. formRef.value?.validate(async (err) => {
  140. if (!err) {
  141. const params: any = {
  142. ...saveModel,
  143. courseTypeCode: saveModel.courseTypeCode?.join(',') || ''
  144. }
  145. let res: any = null
  146. if (props?.item?.id) {
  147. params.id = props.item.id
  148. res = await updateMaterailData(params)
  149. } else {
  150. res = await materialSave(params)
  151. }
  152. if (res?.code == 200) {
  153. message.success('保存成功')
  154. emit('handleSuccess')
  155. } else {
  156. message.warning('保存失败')
  157. }
  158. }
  159. })
  160. }
  161. // 改变素材类型
  162. const changeType = () => {
  163. saveModel.content = ''
  164. musicOpentions.music = ''
  165. }
  166. // 添加曲谱
  167. const musicOpentions = reactive({
  168. show: false,
  169. music: '' as any,
  170. type: ''
  171. })
  172. const hanldeSelectMusic = (musicItem: any) => {
  173. musicOpentions.music = musicItem
  174. saveModel.content = musicItem.id
  175. musicOpentions.show = false
  176. formContentRef.value?.restoreValidation()
  177. // console.log('🚀 ~ musicItem', musicItem)
  178. }
  179. return () => (
  180. <div>
  181. <NSpin show={loading.value}>
  182. <NForm
  183. disabled={props.isLook ? true : false}
  184. ref={formRef}
  185. onSubmit={submit}
  186. labelPlacement="top"
  187. model={saveModel}
  188. rules={rules}
  189. require-mark-placement="left"
  190. >
  191. <NSpace justify="space-between" item-style={{ flex: 1 }}>
  192. <NFormItem label="素材名称" path="name">
  193. <NInput v-model:value={saveModel.name} />
  194. </NFormItem>
  195. <NFormItem label="分段编号" path="sn">
  196. <NInput v-model:value={saveModel.sn} />
  197. </NFormItem>
  198. </NSpace>
  199. <NSpace justify="space-between" item-style={{ flex: 1 }}>
  200. <NFormItem label="素材分类" path="materialCategoryId">
  201. <NCascader
  202. v-model:value={saveModel.materialCategoryId}
  203. placeholder="请选择素材分类"
  204. options={props.categoryList}
  205. checkStrategy="child"
  206. childrenField="subMaterialCategoryList"
  207. expandTrigger="hover"
  208. valueField="id"
  209. labelField="name"
  210. />
  211. </NFormItem>
  212. {/* <NFormItem label="建议学习时长" path="adviseStudyTimeSecond" required>
  213. <NInput
  214. v-model:value={saveModel.adviseStudyTimeSecond}
  215. v-slots={{
  216. suffix: () => '秒'
  217. }}
  218. />
  219. </NFormItem> */}
  220. </NSpace>
  221. <NSpace justify="space-between" item-style={{ flex: 1 }}>
  222. <NFormItem label="课程类型" path="courseTypeCode">
  223. <NSelect
  224. multiple
  225. clearable
  226. disabled={props?.item ? true : false}
  227. value={saveModel.courseTypeCode}
  228. onUpdateValue={(val: any) => {
  229. saveModel.courseTypeCode = val
  230. }}
  231. options={lessonType}
  232. />
  233. </NFormItem>
  234. <NFormItem label="是否启用">
  235. <NSwitch v-model:value={saveModel.enableFlag} />
  236. </NFormItem>
  237. </NSpace>
  238. <NFormItem label="素材类型" required labelPlacement="left" path="type">
  239. <NRadioGroup v-model:value={saveModel.type} onUpdateValue={() => changeType()}>
  240. <NRadio value={materialType.视频}>视频</NRadio>
  241. <NRadio value={materialType.图片}>图片</NRadio>
  242. <NRadio value={materialType.曲目}>曲目</NRadio>
  243. </NRadioGroup>
  244. </NFormItem>
  245. <NSpace justify="space-between" item-style={{ flex: 1 }}>
  246. <NFormItem label="上传素材" path="content" ref={formContentRef} required>
  247. {saveModel.type === materialType.曲目 ? (
  248. <NSpace>
  249. <NButton
  250. disabled={props.isLook}
  251. type="primary"
  252. onClick={() => {
  253. musicOpentions.show = true
  254. musicOpentions.type = 'upload'
  255. }}
  256. >
  257. 选择曲谱
  258. </NButton>
  259. {musicOpentions.music && (
  260. <NInput disabled value={musicOpentions.music?.name}></NInput>
  261. )}
  262. </NSpace>
  263. ) : (
  264. <UploadFile
  265. accept={
  266. saveModel.type === materialType.视频
  267. ? 'video/*'
  268. : saveModel.type === materialType.图片
  269. ? 'image/*'
  270. : ''
  271. }
  272. path="courseware/"
  273. listType={saveModel.type === materialType.图片 ? 'image-card' : 'image'}
  274. v-model:fileList={saveModel.content}
  275. size={1024}
  276. disabled={props.isLook}
  277. onReadFileInputEventAsArrayBuffer={() => {
  278. formContentRef.value?.restoreValidation()
  279. }}
  280. ></UploadFile>
  281. )}
  282. </NFormItem>
  283. {saveModel.type !== 'SONG' && (
  284. <NFormItem label="关联曲目">
  285. <NSpace>
  286. <NButton
  287. disabled={props.isLook}
  288. type="primary"
  289. onClick={() => {
  290. musicOpentions.show = true
  291. musicOpentions.type = 'correlation'
  292. }}
  293. >
  294. 选择曲谱
  295. </NButton>
  296. {saveModel.materialRefs.length > 0 && (
  297. <NInputGroup>
  298. <NInput disabled value={saveModel.materialRefs[0]?.resourceName}></NInput>
  299. <NButton
  300. type="primary"
  301. disabled={props.isLook}
  302. onClick={() => {
  303. saveModel.materialRefs = []
  304. }}
  305. >
  306. 删除
  307. </NButton>
  308. </NInputGroup>
  309. )}
  310. </NSpace>
  311. </NFormItem>
  312. )}
  313. </NSpace>
  314. <NFormItem label="阶段目标" required labelPlacement="left" path="phaseGoals">
  315. <Editor v-model:value={saveModel.phaseGoals}
  316. editorType="simple"
  317. maxLength={1000}
  318. bucketName="news-info"
  319. excludeKeys={[
  320. 'emotion',
  321. 'insertTable',
  322. 'uploadImage',
  323. 'uploadVideo',
  324. 'bulletedList',
  325. 'numberedList',
  326. 'blockquote',
  327. 'divider'
  328. ]} />
  329. </NFormItem>
  330. <NFormItem label="检查事项" required labelPlacement="left" path="checkItem">
  331. <Editor v-model:value={saveModel.checkItem}
  332. maxLength={1000}
  333. editorType="simple"
  334. bucketName="news-info"
  335. excludeKeys={[
  336. 'emotion',
  337. 'insertTable',
  338. 'uploadImage',
  339. 'uploadVideo',
  340. 'bulletedList',
  341. 'numberedList',
  342. 'blockquote',
  343. 'divider'
  344. ]} />
  345. </NFormItem>
  346. </NForm>
  347. {props.isLook ? (
  348. ''
  349. ) : (
  350. <NSpace justify="end">
  351. <NButton type="default" onClick={() => emit('close')}>
  352. 取消
  353. </NButton>
  354. <NButton type="primary" onClick={submit}>
  355. 保存
  356. </NButton>
  357. </NSpace>
  358. )}
  359. </NSpin>
  360. <NDrawer width="80vw" height="100vh" v-model:show={musicOpentions.show}>
  361. <NDrawerContent title="选择曲谱" closable>
  362. <SelectMusicSheet
  363. type={musicOpentions.type}
  364. onSelect={(row: any) => {
  365. console.log(musicOpentions.type, row)
  366. if (musicOpentions.type === 'upload') {
  367. hanldeSelectMusic(row)
  368. } else {
  369. saveModel.materialRefs = [
  370. {
  371. resourceId: row.id,
  372. knowledgeType: 'MUSIC',
  373. resourceName: row.name
  374. }
  375. ]
  376. musicOpentions.show = false
  377. }
  378. }}
  379. />
  380. </NDrawerContent>
  381. </NDrawer>
  382. </div>
  383. )
  384. }
  385. })