index.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. import {
  2. computed,
  3. defineComponent,
  4. nextTick,
  5. onMounted,
  6. reactive,
  7. ref
  8. } from 'vue';
  9. import styles from './index.module.less';
  10. import {
  11. NButton,
  12. NForm,
  13. NFormItem,
  14. NImage,
  15. NInput,
  16. NScrollbar,
  17. NSelect,
  18. NSpace,
  19. NSwitch,
  20. useMessage
  21. } from 'naive-ui';
  22. import UploadFile from './upload-file';
  23. import { useCatchStore } from '/src/store/modules/catchData';
  24. import iconImage from '@common/images/icon-image.png';
  25. import iconVideo from '@common/images/icon-video.png';
  26. import iconAudio from '@common/images/icon-audio.png';
  27. import iconMusic from '@common/images/icon-music.png';
  28. import iconPPT from '@common/images/icon-ppt.png';
  29. import iconUploadDelete from '../../../images/btn-remove.png';
  30. import { materialSave, materialUpdateAll } from '../../../api';
  31. import { NaturalTypeEnum } from '@/enums/pageEnum';
  32. import { scrollToErrorForm } from '/src/utils';
  33. // 判断链接后辍
  34. export const formatUrlType = (url: string) => {
  35. if (!url) return '';
  36. if (url?.indexOf('.mp3') > -1) {
  37. return NaturalTypeEnum.SONG;
  38. } else if (url?.indexOf('.mp4') > -1) {
  39. return NaturalTypeEnum.VIDEO;
  40. } else if (url?.indexOf('.ppt') > -1) {
  41. return NaturalTypeEnum.PPT;
  42. } else {
  43. return NaturalTypeEnum.IMG;
  44. }
  45. };
  46. export default defineComponent({
  47. name: 'upload-modal',
  48. props: {
  49. list: {
  50. type: Array,
  51. default: () => []
  52. },
  53. editStatus: {
  54. type: Boolean,
  55. default: true
  56. }
  57. },
  58. emits: ['close', 'confirm', 'editAll'],
  59. setup(props, { emit }) {
  60. const catchStore = useCatchStore();
  61. const formRef = ref();
  62. const message = useMessage();
  63. const uploadRef = ref();
  64. const uploadList = ref([] as any);
  65. const uploadForms = reactive({
  66. list: [] as any[],
  67. uploading: false,
  68. uploadUrl: '',
  69. name: '',
  70. subjectIds: [] as any
  71. });
  72. // 判断类型
  73. const formatType = (type: string) => {
  74. let typeImg = iconImage;
  75. switch (type) {
  76. case 'IMG':
  77. typeImg = iconImage;
  78. break;
  79. case 'VIDEO':
  80. typeImg = iconVideo;
  81. break;
  82. case 'SONG':
  83. typeImg = iconAudio;
  84. break;
  85. case 'MUSIC':
  86. typeImg = iconMusic;
  87. break;
  88. case 'PPT':
  89. typeImg = iconPPT;
  90. break;
  91. }
  92. return typeImg;
  93. };
  94. const onSubmit = async () => {
  95. //
  96. formRef.value?.validate(async (err: any) => {
  97. if (err) {
  98. nextTick(scrollToErrorForm);
  99. return;
  100. }
  101. uploadForms.uploading = true;
  102. try {
  103. const body: any[] = [];
  104. uploadForms.list.forEach(item => {
  105. body.push({
  106. subjectIds: item.subjectIds.join(','),
  107. openFlag: item.openFlag,
  108. coverImg: item.coverImg,
  109. name: item.name,
  110. type: item.type,
  111. enableFlag: 1,
  112. content: item.content,
  113. id: item.id || null
  114. });
  115. });
  116. if (isUpdate.value) {
  117. // await materialUpdateAll(body);
  118. emit('editAll', body);
  119. uploadForms.list = [];
  120. } else {
  121. await materialSave(body);
  122. message.success('保存成功');
  123. uploadForms.list = [];
  124. emit('close', true);
  125. emit('confirm');
  126. }
  127. } catch {
  128. //
  129. }
  130. uploadForms.uploading = false;
  131. });
  132. };
  133. const handleRemove = (index: number) => {
  134. uploadForms.list.splice(index, 1);
  135. };
  136. const isUpdate = computed(() => (props.list.length > 0 ? true : false));
  137. onMounted(async () => {
  138. const list = props.list || [];
  139. const temps: any[] = [];
  140. list.forEach((item: any) => {
  141. temps.push({
  142. subjectIds: item.subjectId
  143. ? item.subjectId
  144. .split(',')
  145. .map((subjectId: any) => Number(subjectId))
  146. : [],
  147. openFlag: item.openFlag,
  148. coverImg: item.coverImg,
  149. name: item.title,
  150. type: item.type,
  151. sourceFrom: item.sourceFrom,
  152. enableFlag: item.enableFlag,
  153. content: item.content,
  154. id: item.id
  155. });
  156. });
  157. uploadForms.list = temps || [];
  158. // console.log(temps, 'uploadForms');
  159. await catchStore.getSubjects();
  160. });
  161. // 全选
  162. const chioseAll = (item: any, list: any) => {
  163. item.subjectIds = list.map((item: any) => {
  164. return item.id;
  165. }) as any;
  166. };
  167. return () => (
  168. <div class={styles.uploadModal}>
  169. <NScrollbar style={{ 'max-height': '55vh' }}>
  170. <NForm
  171. ref={formRef}
  172. labelPlacement="left"
  173. labelWidth={120}
  174. model={uploadForms}
  175. class={styles.formModal}>
  176. <NSpace class={styles.formSpace}>
  177. {uploadForms.list.map((item: any, index: number) => (
  178. <div class={styles.formItem} key={index}>
  179. <div class={styles.previewModal}>
  180. <NImage
  181. class={[styles.titleType]}
  182. src={formatType(item.type)}
  183. previewDisabled
  184. objectFit="cover"
  185. />
  186. {/* 编辑时不能删除 */}
  187. {!isUpdate.value && (
  188. <img
  189. class={[styles.iconUploadDelete]}
  190. src={iconUploadDelete}
  191. onClick={() => handleRemove(index)}
  192. />
  193. )}
  194. <NImage
  195. class={[styles.cover, styles.image]}
  196. lazy
  197. previewDisabled
  198. src={item.coverImg}
  199. objectFit="cover"
  200. />
  201. <div class={styles.commonType}>
  202. 是否公开:
  203. <NSwitch
  204. size="small"
  205. v-model:value={item.openFlag}
  206. disabled={
  207. item.sourceFrom === 'TEACHER' && item.type === 'MUSIC'
  208. }
  209. />
  210. </div>
  211. </div>
  212. <NFormItem
  213. showFeedback={false}
  214. path={`list.${index}.name`}
  215. rule={[
  216. {
  217. required: true,
  218. message: '请输入资源名称',
  219. trigger: ['input', 'blur']
  220. }
  221. ]}>
  222. <NInput
  223. v-model:value={item.name}
  224. placeholder="请输入资源名称"
  225. maxlength={25}
  226. clearable
  227. />
  228. </NFormItem>
  229. <NFormItem
  230. path={`list[${index}].subjectIds`}
  231. showFeedback={false}
  232. rule={[
  233. {
  234. required: true,
  235. message: '请选择素材可用声部',
  236. trigger: 'change',
  237. type: 'array'
  238. }
  239. ]}>
  240. <NSelect
  241. v-model:value={item.subjectIds}
  242. placeholder="请选择素材可用声部(可多选)"
  243. options={catchStore.getSubjectList}
  244. labelField="name"
  245. valueField="id"
  246. multiple
  247. maxTagCount={2}
  248. clearable
  249. v-slots={{
  250. action: () => (
  251. <>
  252. <NButton
  253. text
  254. style=" --n-width: 100% "
  255. onClick={() =>
  256. chioseAll(item, catchStore.getSubjectList)
  257. }>
  258. 全选
  259. </NButton>
  260. </>
  261. )
  262. }}
  263. />
  264. </NFormItem>
  265. </div>
  266. ))}
  267. {/* {!isUpdate.value && (
  268. <div class={styles.formItem}>
  269. <UploadFile
  270. v-model:fileList={uploadForms.uploadUrl}
  271. accept=".jpg,jpeg,.png,audio/mp3,video/mp4"
  272. showFileList={false}
  273. ref={uploadRef}
  274. // cropper
  275. multiple
  276. max={10}
  277. // options={{
  278. // autoCropWidth: 320,
  279. // autoCropHeight: 180,
  280. // fixedBox: true
  281. // }}
  282. onFinished={(val: any) => {
  283. console.log(val, 'val');
  284. uploadList.value.push({
  285. subjectIds: uploadForms.subjectIds || [],
  286. openFlag: true,
  287. coverImg: val.coverImg,
  288. name: uploadForms.name || '',
  289. type: formatUrlType(val.content),
  290. enableFlag: 1,
  291. content: val.content
  292. });
  293. // uploadForms.list.push({
  294. // subjectIds: uploadForms.subjectIds || [],
  295. // openFlag: true,
  296. // coverImg: val.coverImg,
  297. // name: uploadForms.name || '',
  298. // type: formatUrlType(val.content),
  299. // enableFlag: 1,
  300. // content: val.content
  301. // });
  302. const timer = setTimeout(() => {
  303. uploadForms.list.push(...uploadList.value);
  304. uploadList.value = [];
  305. uploadForms.uploadUrl = '';
  306. uploadForms.name = '';
  307. uploadForms.subjectIds = [];
  308. uploadRef.value.handleClearFile();
  309. }, 1000);
  310. }}
  311. />
  312. <NFormItem showFeedback={false}>
  313. <NInput
  314. v-model:value={uploadForms.name}
  315. placeholder="请输入资源名称"
  316. maxlength={25}
  317. clearable
  318. />
  319. </NFormItem>
  320. <NFormItem showFeedback={false}>
  321. <NSelect
  322. v-model:value={uploadForms.subjectIds}
  323. placeholder="请选择素材可用声部(可多选)"
  324. options={catchStore.getSubjectList}
  325. labelField="name"
  326. valueField="id"
  327. multiple
  328. maxTagCount={2}
  329. clearable
  330. v-slots={{
  331. action: () => (
  332. <>
  333. <NButton
  334. text
  335. style=" --n-width: 100% "
  336. onClick={() =>
  337. chioseAll(
  338. uploadForms,
  339. catchStore.getSubjectList
  340. )
  341. }>
  342. 全选
  343. </NButton>
  344. </>
  345. )
  346. }}
  347. />
  348. </NFormItem>
  349. </div>
  350. )} */}
  351. </NSpace>
  352. </NForm>
  353. </NScrollbar>
  354. <NSpace class={styles.btnGroup} justify="center">
  355. <NButton round onClick={() => emit('close')}>
  356. {props.editStatus ? '取消' : '上一步'}
  357. </NButton>
  358. <NButton
  359. round
  360. type="primary"
  361. loading={uploadForms.uploading}
  362. disabled={uploadForms.list.length === 0}
  363. onClick={onSubmit}>
  364. 确定
  365. </NButton>
  366. </NSpace>
  367. </div>
  368. );
  369. }
  370. });