instrument-edit.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. const Editor = window.createEditorComponent()
  2. const app = new Vue({
  3. components: {
  4. Editor,
  5. },
  6. data() {
  7. var validateQuestionList = (rule, value, callback) => {
  8. if (!value) {
  9. callback(new Error('问答列表不能为空'))
  10. } else if (value < this.minLimitQuestions) {
  11. callback(new Error(`请填写至少${this.minLimitQuestions}条问答`))
  12. } else {
  13. callback();
  14. }
  15. }
  16. var validateParamList = (rule, value, callback) => {
  17. if (!value) {
  18. callback(new Error('参数列表不能为空'))
  19. } else if (value < this.minLimitParams) {
  20. callback(new Error(`请填写至少${this.minLimitParams}条参数`))
  21. } else {
  22. callback();
  23. }
  24. }
  25. return {
  26. productId: 0,
  27. commodityType: 2, // 商品类型 1: 产品 2: 仪器
  28. shopId: GLOBAL_SHOP_ID,
  29. action: $('#coreServer').val() + '/tools/image/upload/multi',
  30. formData: {
  31. // 仪器名称
  32. name: '',
  33. // 仪器别名
  34. alias: '',
  35. // 仪器概述
  36. discription: '',
  37. // 仪器图片
  38. image: '',
  39. // 认证链接
  40. authLink: '',
  41. // 认证二维码
  42. authQrCode: '',
  43. // 仪器参数
  44. paramList: '',
  45. // 仪器优点
  46. advantage: '',
  47. // 仪器缺点
  48. disadvantage: '',
  49. // 仪器原理
  50. principle: '',
  51. // 品牌
  52. brand: '',
  53. // 产地
  54. producePlace: '',
  55. // 上市时间
  56. marketTime: '',
  57. // 供应商
  58. company: '',
  59. // NMPA认证时间
  60. nmpaTime: '',
  61. // 仪器认证
  62. authImageList: '',
  63. // 适应证
  64. adaptiveMan: '',
  65. // 不适应人群
  66. unAdaptiveMan: '',
  67. // 注意事项
  68. aroundOperation: '',
  69. // 效果展示图片列表
  70. // displayImageList: '',
  71. // 常见问题
  72. questionList: '',
  73. // 仪器类别
  74. typeId: '',
  75. // 仪器状态
  76. status: 1,
  77. // seo关键词
  78. seoKeyword: '',
  79. // 仪器链接
  80. productLink: '',
  81. },
  82. rules: {
  83. // 仪器名称
  84. name: [{required: true, message: '仪器名称不能为空', trigger: ['change', 'blur']}],
  85. // 仪器别名
  86. alias: [{required: true, message: '仪器别名不能为空', trigger: ['change', 'blur']}],
  87. // 仪器概述
  88. discription: [{required: true, message: '仪器概述不能为空', trigger: ['change', 'blur']}],
  89. // 仪器图片
  90. image: [{required: true, message: '请上传仪器图片', trigger: 'change'}],
  91. // 产品链接
  92. productLink: [{required: true, message: '产品链接不能为空', trigger: ['change', 'blur']}],
  93. // 产仪器参数
  94. paramList: [{required: true, validator: validateParamList, trigger: 'change'}],
  95. // // 认证链接
  96. // authLink: [{required: true, message: '请输入认证链接', trigger: ['change', 'blur']}],
  97. // // 认证二维码
  98. // authQrCode: [{required: true, message: '请上传证二维码', trigger: 'change'}],
  99. // // 仪器优点
  100. // advantage: [{required: true, message: '仪器优点不能为空', trigger: 'change'}],
  101. // // 仪器缺点
  102. // disadvantage: [{required: true, message: '仪器缺点不能为空', trigger: 'change'}],
  103. // // 仪器原理
  104. // principle: [{required: true, message: '仪器原理不能为空', trigger: 'change'}],
  105. // // 品牌
  106. // brand: [{required: true, message: '请输入仪器品牌', trigger: ['change', 'blur']}],
  107. // // 产地
  108. // producePlace: [{required: true, message: '仪器产地不能为空', trigger: ['change', 'blur']}],
  109. // // 上市时间
  110. // marketTime: [{required: true, message: '请填写上市时间', trigger: 'change'}],
  111. // // 供应商
  112. // company: [{required: true, message: '公司/厂商不能为空', trigger: ['change', 'blur']}],
  113. // // NMPA认证时间
  114. // nmpaTime: [{required: true, message: '请填写NMPA认证时间', trigger: 'change'}],
  115. // // 仪器认证
  116. // authImageList: [{required: true, message: '请上传仪器认证图片', trigger: 'change'}],
  117. // // 适应证
  118. // adaptiveMan: [{required: true, message: '适应人群不能为空', trigger: 'change'}],
  119. // // 不适应人群
  120. // unAdaptiveMan: [{required: true, message: '不适应人群不能为空', trigger: 'change'}],
  121. // // 术前术后
  122. // aroundOperation: [{required: true, message: '术前术后不能为空', trigger: 'change'}],
  123. // // 效果展示图片列表
  124. // displayImageList: [{required: true, message: '请上传效果展示图片', trigger: 'change'}],
  125. // // 常见问题
  126. // questionList: [{required: true, validator: validateQuestionList, trigger: 'change'}],
  127. // // 仪器类别
  128. // typeId: [{required: true, message: '请选择仪器类别', trigger: 'change'}],
  129. // // 仪器状态
  130. // status: [{required: true, message: '请选择仪器状态', trigger: 'change'}],
  131. },
  132. // 仪器类别列表
  133. typeList: [],
  134. // 仪器参数
  135. // paramList: [],
  136. paramEmptyList: [], // 占位
  137. minLimitParams: 2,
  138. // 常见问题
  139. questionEmptyList: [], // 占位
  140. minLimitQuestions: 2,
  141. // 仪器认证
  142. authImageList: [],
  143. // 效果展示图片列表
  144. displayImageList: [], // 初始化列表
  145. dialogVisible: false,
  146. dialogImageUrl: '',
  147. // 日期选择格式
  148. marketTimeType: 'year',
  149. nmpaTimeType: 'year',
  150. // 空缺数量
  151. emptyNum: ''
  152. }
  153. },
  154. computed: {
  155. // 仪器参数
  156. paramList() {
  157. const filter = this.paramEmptyList.filter(param => param.content !== '' && param.name !== '')
  158. if (filter.length > 0) return filter.map(param => ({name: param.name, content: param.content}))
  159. return []
  160. },
  161. // 常见问题
  162. questionList() {
  163. const filter = this.questionEmptyList.filter(item => item.question !== '' && item.answer !== '')
  164. if (filter.length > 0) return filter.map(item => ({question: item.question, answer: item.answer}))
  165. return []
  166. }
  167. },
  168. mounted: function mounted() {
  169. $('.navLayout').find('.navList').removeClass("on").find('.con').hide().find('a').removeClass("on");
  170. $('.navLayout').find('.navList').eq(3).addClass("on").find('.con').show().find('a').eq(1).addClass("on");
  171. },
  172. created() {
  173. this.getTypeList();
  174. this.watchArrayStatus(['paramList', 'questionList', 'authImageList']);
  175. this.getProductFormData();
  176. },
  177. methods: {
  178. // 返回文章列表页面
  179. handleBack: function handleBack() {
  180. localStorage.removeItem('target-name');
  181. window.open('/supplier/encyclopedia/instrument-list.html', 'supplier-instrument-list');
  182. window.close();
  183. },
  184. // 保存事件
  185. handleSave() {
  186. this.$refs.ruleForm.validate(valide => {
  187. console.log(valide);
  188. if (!valide) {
  189. this.socrllToErrorInput()
  190. return;
  191. }
  192. this.emptyNum = this.validateEmptyParams(this.formData)
  193. if( this.emptyNum> 0){
  194. this.$confirm('您还剩余' + this.emptyNum + '项未完善,将会导致用户对您产品/仪器的认识度不够,确认是否提交?', '提示', {
  195. confirmButtonText: '是',
  196. cancelButtonText: '否'
  197. }).then(() => {
  198. this.saveFormData()
  199. })
  200. } else{
  201. this.saveFormData()
  202. }
  203. })
  204. },
  205. // 校验空参数个数
  206. validateEmptyParams(params){
  207. const keys = Object.keys(params)
  208. console.log(params)
  209. let count = 0
  210. keys.forEach(key => {
  211. if(typeof params[key] === "string"){
  212. if(params[key] === '' || params[key].trim().length <= 0){
  213. count ++
  214. }
  215. }else if(typeof params[key] === 'number'){
  216. console.log(key)
  217. }else if(typeof params[key] === 'object'){
  218. if(params[key] instanceof Array){
  219. if(params[key].length <= 0){
  220. count ++
  221. }
  222. }else {
  223. if(params[key] === null){
  224. count ++
  225. }
  226. }
  227. }else if(typeof params[key] === 'undefined'){
  228. count ++
  229. }
  230. })
  231. return count;
  232. },
  233. // 裁切时间格式
  234. sliceDateStr(time, type) {
  235. time = dateFormat(time, 'yyyy-MM-dd')
  236. if (type === 'year') {
  237. time = time.slice(0, 4)
  238. } else if (type === 'month') {
  239. time = time.slice(0, 7)
  240. }
  241. return time
  242. },
  243. // 保存表单数据
  244. saveFormData() {
  245. const that = this;
  246. const params = {
  247. ...this.formData,
  248. shopId: this.shopId,
  249. commodityType: this.commodityType,
  250. paramList: JSON.stringify(this.paramList),
  251. questionList: JSON.stringify(this.questionList),
  252. // marketTime: dateFormat(this.formData.marketTime, 'yyyy-MM-dd'),
  253. // nmpaTime: dateFormat(this.formData.nmpaTime, 'yyyy-MM-dd'),
  254. authImageList: this.authImageList.map(image => (image.response ? image.response.data : image.url)),
  255. // displayImageList: this.displayImageList.map(image => (image.response ? image.response.data : image.url))
  256. };
  257. /* 处理时间 */
  258. if(this.formData.marketTime){
  259. params.marketTime = this.sliceDateStr(this.formData.marketTime, this.marketTimeType)
  260. }
  261. /* 处理时间 */
  262. if(this.formData.nmpaTime){
  263. params.nmpaTime = this.sliceDateStr(this.formData.nmpaTime, this.nmpaTimeType)
  264. }
  265. if (this.productId) params.productId = this.productId;
  266. params.emptyNum = this.emptyNum;
  267. console.log(params);
  268. SupplierApi.ShopBaikeProductSave(params, function (res) {
  269. if (res.code === 0) {
  270. CAIMEI.dialog('保存成功', false);
  271. setTimeout(function () {
  272. that.handleBack();
  273. }, 2000);
  274. } else {
  275. CAIMEI.Alert(res.msg, '确认', false)
  276. }
  277. })
  278. },
  279. // 获取时间类型(年月日)
  280. getTimeType(time){
  281. time = time.split('-')
  282. if(time.length === 1){
  283. return 'year'
  284. }else if(time.length === 2){
  285. return 'month'
  286. }else {
  287. return 'date'
  288. }
  289. },
  290. initFormData: function(formData){
  291. console.log(formData);
  292. // 初始化this.formData
  293. for (var key in this.formData) {
  294. if (formData.hasOwnProperty(key)) {
  295. // 如果是数组 就取值length
  296. if(formData[key] instanceof Array){
  297. const len = formData[key].length
  298. this.formData[key] = len > 0 ? len : ''
  299. } else if(['marketTime', 'nmpaTime'].includes(key)){
  300. this.formData[key] = new Date(formData[key])
  301. if(key === 'marketTime'){
  302. this.marketTimeType = this.getTimeType(formData[key])
  303. }else{
  304. this.nmpaTimeType = this.getTimeType(formData[key])
  305. }
  306. }
  307. else {
  308. this.formData[key] = formData[key];
  309. }
  310. }
  311. }
  312. // 处理参数
  313. this.resetEmptyListData(formData.paramList, formData.questionList);
  314. // 处理图片
  315. this.authImageList = formData.authImageList.map(image => ({ url: image, name: 'authImage'}))
  316. // this.displayImageList = formData.displayImageList.map(image => ({ url: image, name: 'authImage'}))
  317. },
  318. // 获取表单数据
  319. getProductFormData() {
  320. this.productId = localStorage.getItem('productId') || 0;
  321. localStorage.removeItem('productId');
  322. if (this.productId > 0) {
  323. const that = this;
  324. SupplierApi.GetShopBaikeProductForm({productId: this.productId}, function (res) {
  325. if (res.code === 0) {
  326. that.initFormData(res.data);
  327. } else {
  328. CAIMEI.dialog('获取仪器数据失败', false);
  329. setTimeout(function () {
  330. that.handleBack();
  331. }, 2000);
  332. }
  333. });
  334. }else {
  335. this.resetEmptyListData([],[])
  336. }
  337. },
  338. // 获取分类列表
  339. getTypeList() {
  340. const that = this;
  341. SupplierApi.ShopBaikeProductTypeList({commodityType: this.commodityType}, function (res) {
  342. that.typeList = res.data;
  343. console.log(res);
  344. })
  345. },
  346. //添加一条参数
  347. addParam() {
  348. this.paramEmptyList.push({
  349. name: '',
  350. content: '',
  351. p1: '参数名',
  352. p2: '参数信息',
  353. })
  354. },
  355. // 删除一条参数
  356. removeParam(index) {
  357. this.paramEmptyList.splice(index, 1)
  358. },
  359. //添加一条问答
  360. addQuestion() {
  361. this.questionEmptyList.push({
  362. question: '',
  363. answer: '',
  364. p1: '请输入问题内容',
  365. p2: '请输入问题解答内容',
  366. })
  367. },
  368. // 删除一条问答
  369. removeQuestion(index) {
  370. this.questionEmptyList.splice(index, 1)
  371. },
  372. // 初始化可变表单数据
  373. resetEmptyListData(paramSource, questionSource) {
  374. this.makeEmptyList({
  375. target: this.paramEmptyList,
  376. source: paramSource,
  377. limit: this.minLimitParams,
  378. key: 'name',
  379. value: 'content',
  380. })
  381. this.makeEmptyList({
  382. target: this.questionEmptyList,
  383. source: questionSource,
  384. limit: this.minLimitQuestions,
  385. key: 'question',
  386. value: 'answer',
  387. })
  388. },
  389. // 创建可变表单占位列表
  390. makeEmptyList(options) {
  391. options = {
  392. target: [], // 目标数组
  393. source: [], // 数据源数组
  394. key: '',
  395. value: '',
  396. limit: 0, // 最小条数
  397. argsList: ['参数', '品牌'], // placeholder文本
  398. ...options,
  399. }
  400. let {target, source, limit, argsList, key, value} = options
  401. let len = 0
  402. target.push(
  403. ...source.map(v => {
  404. v.p1 = `例如:${argsList[0]}`
  405. v.p2 = `请输入:${argsList[0]}信息`
  406. return v
  407. })
  408. )
  409. len = limit - target.length
  410. for (let i = 0; i < len; i++) {
  411. const obj = {}
  412. obj[key] = ''
  413. obj[value] = ''
  414. if (i <= argsList.length - 1) {
  415. obj.p1 = `例如:${argsList[i]}`
  416. obj.p2 = `请输入:${argsList[i]}信息`
  417. } else {
  418. obj.p1 = `例如:${argsList[0]}`
  419. obj.p2 = `请输入:${argsList[0]}信息`
  420. }
  421. target.push(obj)
  422. }
  423. },
  424. handleAuthQrCodeSuccess(response){
  425. this.$refs.authQrCodeUploader.clearFiles();
  426. this.formData.authQrCode = response.data
  427. },
  428. // 仪器图片上传成功的回调
  429. handleImageSuccess(response) {
  430. this.$refs.coverUploader.clearFiles();
  431. this.formData.image = response.data
  432. },
  433. // 认证图片上传成功的回调
  434. handleAuthImageSuccess(response, file, fileList) {
  435. this.authImageList = fileList
  436. },
  437. // 移除认证图片
  438. handleAuthImageRemove(file, fileList) {
  439. // console.log(fileList)
  440. this.authImageList = fileList
  441. },
  442. // 效果图片上传成功的回调
  443. handleDisplayImageSuccess(response, file, fileList) {
  444. this.displayImageList = fileList
  445. },
  446. // 移除效果图片
  447. handleDisplayImageRemove(file, fileList) {
  448. this.displayImageList = fileList
  449. },
  450. // 图片上传前的回调
  451. beforeImageUpload(file) {
  452. const isLt2M = file.size / 1024 / 1024 < 2
  453. if (!isLt2M) {
  454. this.$message.error('上传头像图片大小不能超过 2MB!')
  455. }
  456. return isLt2M
  457. },
  458. // 预览图片
  459. handlePictureCardPreview(file) {
  460. this.dialogImageUrl = file.url
  461. this.dialogVisible = true
  462. },
  463. // 预览图片弹窗
  464. handlePictureCardPreview(file) {
  465. this.dialogImageUrl = file.url
  466. this.dialogVisible = true
  467. },
  468. // 监听formData中类型为数组的数据状态
  469. watchArrayStatus(args = []) {
  470. args.forEach(arg => {
  471. if (this[arg] instanceof Array) {
  472. this.$watch(
  473. arg,
  474. (nval, oval) => {
  475. console.log(arg, nval.length);
  476. console.log(this[arg]);
  477. if(nval.length > 0){
  478. this.formData[arg] = nval.length
  479. } else{
  480. this.formData[arg] = ''
  481. }
  482. },
  483. {deep: true}
  484. )
  485. }
  486. })
  487. },
  488. // 滚动到必填位置
  489. socrllToErrorInput(){
  490. this.$nextTick(() => {
  491. const scrollTop = $('.el-form-item__error').eq(0).parent().siblings('.el-form-item__label').offset().top
  492. $('body,html').animate({
  493. scrollTop: scrollTop - $('#globalHead').height() - 40
  494. }, 800)
  495. })
  496. }
  497. },
  498. })
  499. app.$mount('#instrumentEdit')