xiebaomin 1 年之前
父節點
當前提交
ca4398e836

+ 9 - 0
src/api/contentLibrary/context.js

@@ -33,6 +33,15 @@ export const uploadFile = (data) => request({
   data
 })
 
+export const uploadFileNew = (data) => request({
+  url: 'https://core-b.caimei365.com/tools/file/upload/oss',
+  method: 'POST',
+  headers: {
+    'Content-Type': 'multipart/form-data'
+  },
+  data
+})
+
 export const deleteContext = (data) => request({
   url: '/productArchive/content/del',
   method: 'POST',

+ 1 - 1
src/utils/request.js

@@ -7,7 +7,7 @@ import { getToken } from '@/utils/auth'
 const service = axios.create({
   baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
   // withCredentials: true, // send cookies when cross-domain requests
-  timeout: 10000 // request timeout
+  timeout: 25000 // request timeout
 })
 
 // request interceptor

+ 4 - 1
src/views/dataBase/components/UploadFile.vue

@@ -132,12 +132,15 @@ export default {
     async handleChange(file) {
       console.log(file)
       const f = file.target.files[0]
+      console.log(f)
       const formData = new FormData()
+      const isType = this.accept.indexOf('.pdf') !== -1
       formData.append('multipartFile', f)
+      formData.append('type', isType ? 1 : '')
       try {
         this.$emit('change-loading')
         const data = await uploadFile(formData)
-        if (data.success) {
+        if (data.success || data.code === 0) {
           this.dataList.push({ fileName: data.fileName, ossUrl: data.url, ossName: data.ossName })
           this.$emit('success', { fileList: this.dataList })
           this.$emit('change-loading')

+ 1 - 1
src/views/dataBase/components/dialogTable.vue

@@ -3,7 +3,7 @@
     <div class="filter-container">
       <div class="filter-control">
         <span>商品ID:</span>
-        <el-input v-model="listQuery.productId" size="mini" placeholder="商品ID" @keyup.enter.native="filterList" />
+        <el-input v-model="listQuery.productId" size="mini" placeholder="商品ID" type="number" @keyup.enter.native="filterList" />
       </div>
       <div class="filter-control">
         <span>商品名称:</span>

+ 2 - 2
src/views/dataBase/store-list/data-management/edit.vue

@@ -208,8 +208,8 @@ export default {
       })
     },
     handleSelect(val) {
-      console.log(val)
-      this.form.labelIds = val.map(e => e.k).join(',')
+      console.log(val, '标签')
+      this.form.labelIds = val.map(e => e.id).join(',')
       console.log(this.form.labelIds)
     }
   }

+ 129 - 129
src/views/wechat/components/textForm.vue

@@ -1,129 +1,129 @@
-<template>
-  <div class="app-container">
-    <el-page-header :content="isEdit?'编辑文本素材':'添加文本素材'" @back="goBack" />
-    <el-card class="form-container" shadow="never">
-      <el-form ref="weChatTextFrom" :model="text" :rules="rules" label-width="150px">
-        <el-form-item label="标题:" prop="title">
-          <el-input v-model="text.title" />
-        </el-form-item>
-        <el-form-item label="内容:" prop="content">
-          <el-input v-model="text.content" type="textarea" />
-        </el-form-item>
-        <el-form-item>
-          <el-button type="primary" @click="onSubmit('weChatTextFrom')">提交</el-button>
-          <el-button v-if="!isEdit" type="info" @click="resetForm('weChatTextFrom')">重置</el-button>
-          <el-button @click="goBack">返回</el-button>
-        </el-form-item>
-      </el-form>
-    </el-card>
-  </div>
-</template>
-<script>
-import { getText, updateText, createText } from '@/api/wechat/text'
-const defaultText = {
-  id: '',
-  title: '',
-  content: '',
-  type: ''
-}
-export default {
-  name: 'WeChatTextForm',
-  props: {
-    // type 类型: 1采美,2呵呵商城
-    type: {
-      type: Number,
-      default: 0
-    }
-  },
-  data() {
-    return {
-      rules: {
-        title: [{ required: true, message: '标题不能为空', trigger: 'blur' }]
-      },
-      text: Object.assign({}, defaultText),
-      isEdit: false
-    }
-  },
-  watch: {
-    $route(route) {
-      this.getFormData()
-    }
-  },
-  created() {
-    this.getFormData()
-  },
-  methods: {
-    goBack() {
-      // 调用全局挂载的方法,关闭当前标签页
-      this.$store.dispatch('tagsView/delView', this.$route)
-      // 返回上一步路由,返回上一个标签页
-      this.$router.go(-1)
-    },
-    getFormData() {
-      if (this.$route.query.id) {
-        this.text.id = this.$route.query.id
-        this.isEdit = true
-        getText(this.text.id).then(response => {
-          this.text.title = response.data.title
-          this.text.content = response.data.content
-        })
-      } else {
-        this.text.id = ''
-        this.isEdit = false
-        this.text = Object.assign({}, defaultText)
-      }
-      this.text.type = this.type
-    },
-    resetForm(formName) {
-      this.$refs[formName].resetFields()
-      this.text = Object.assign({}, defaultText)
-      this.getFormData()
-    },
-    onSubmit(formName) {
-      this.$refs[formName].validate(valid => {
-        console.log(this.text)
-        if (valid) {
-          this.$confirm('是否提交数据', '提示', {
-            confirmButtonText: '确定',
-            cancelButtonText: '取消',
-            type: 'warning'
-          }).then(() => {
-            const self = this
-            if (this.isEdit) {
-              updateText(this.$route.query.id, this.text).then(response => {
-                this.$message({
-                  message: '修改成功',
-                  type: 'success',
-                  duration: 1000
-                })
-                self.goBack()
-              })
-            } else {
-              createText(this.text).then(response => {
-                this.$refs[formName].resetFields()
-                this.resetForm(formName)
-                this.$message({
-                  message: '提交成功',
-                  type: 'success',
-                  duration: 1000
-                })
-                self.goBack()
-              })
-            }
-          })
-        } else {
-          this.$message({
-            message: '验证失败',
-            type: 'error',
-            duration: 1000
-          })
-          return false
-        }
-      })
-    }
-  }
-}
-</script>
-
-<style scoped>
-</style>
+<template>
+  <div class="app-container">
+    <el-page-header :content="isEdit?'编辑文本素材':'添加文本素材'" @back="goBack" />
+    <el-card class="form-container" shadow="never">
+      <el-form ref="weChatTextFrom" :model="text" :rules="rules" label-width="150px">
+        <el-form-item label="标题:" prop="title">
+          <el-input v-model="text.title" />
+        </el-form-item>
+        <el-form-item label="内容:" prop="content">
+          <el-input v-model="text.content" type="textarea" />
+        </el-form-item>
+        <el-form-item>
+          <el-button type="primary" @click="onSubmit('weChatTextFrom')">提交</el-button>
+          <el-button v-if="!isEdit" type="info" @click="resetForm('weChatTextFrom')">重置</el-button>
+          <el-button @click="goBack">返回</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+  </div>
+</template>
+<script>
+import { getText, updateText, createText } from '@/api/wechat/text'
+const defaultText = {
+  id: '',
+  title: '',
+  content: '',
+  type: ''
+}
+export default {
+  name: 'WeChatTextForm',
+  props: {
+    // type 类型: 1采美,2呵呵商城
+    type: {
+      type: Number,
+      default: 0
+    }
+  },
+  data() {
+    return {
+      rules: {
+        title: [{ required: true, message: '标题不能为空', trigger: 'blur' }]
+      },
+      text: Object.assign({}, defaultText),
+      isEdit: false
+    }
+  },
+  watch: {
+    $route(route) {
+      this.getFormData()
+    }
+  },
+  created() {
+    this.getFormData()
+  },
+  methods: {
+    goBack() {
+      // 调用全局挂载的方法,关闭当前标签页
+      this.$store.dispatch('tagsView/delView', this.$route)
+      // 返回上一步路由,返回上一个标签页
+      this.$router.go(-1)
+    },
+    getFormData() {
+      if (this.$route.query.id) {
+        this.text.id = this.$route.query.id
+        this.isEdit = true
+        getText(this.text.id).then(response => {
+          this.text.title = response.data.title
+          this.text.content = response.data.content
+        })
+      } else {
+        this.text.id = ''
+        this.isEdit = false
+        this.text = Object.assign({}, defaultText)
+      }
+      this.text.type = this.type
+    },
+    resetForm(formName) {
+      this.$refs[formName].resetFields()
+      this.text = Object.assign({}, defaultText)
+      this.getFormData()
+    },
+    onSubmit(formName) {
+      this.$refs[formName].validate(valid => {
+        console.log(this.text)
+        if (valid) {
+          this.$confirm('是否提交数据', '提示', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning'
+          }).then(() => {
+            const self = this
+            if (this.isEdit) {
+              updateText(this.$route.query.id, this.text).then(response => {
+                this.$message({
+                  message: '修改成功',
+                  type: 'success',
+                  duration: 1000
+                })
+                self.goBack()
+              })
+            } else {
+              createText(this.text).then(response => {
+                this.$refs[formName].resetFields()
+                this.resetForm(formName)
+                this.$message({
+                  message: '提交成功',
+                  type: 'success',
+                  duration: 1000
+                })
+                self.goBack()
+              })
+            }
+          })
+        } else {
+          this.$message({
+            message: '验证失败',
+            type: 'error',
+            duration: 1000
+          })
+          return false
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+</style>

+ 16 - 16
src/views/wechat/hehe/article/form.vue

@@ -1,16 +1,16 @@
-<template>
-  <article-form :type="wechatType" />
-</template>
-<script>
-import ArticleForm from '../../components/articleForm'
-export default {
-  name: 'WeChatHeArticleEdit',
-  components: { ArticleForm },
-  data: function() {
-    return {
-      // wechatType 类型: 1采美,2呵呵商城
-      wechatType: 2
-    }
-  }
-}
-</script>
+<template>
+  <article-form :type="wechatType" />
+</template>
+<script>
+import ArticleForm from '../../components/articleForm'
+export default {
+  name: 'WeChatHeArticleEdit',
+  components: { ArticleForm },
+  data: function() {
+    return {
+      // wechatType 类型: 1采美,2呵呵商城
+      wechatType: 2
+    }
+  }
+}
+</script>

+ 16 - 16
src/views/wechat/hehe/article/list.vue

@@ -1,16 +1,16 @@
-<template>
-  <article-list :list-type="wechatType" />
-</template>
-<script>
-import ArticleList from '../../components/articleList'
-export default {
-  name: 'WeChatHeArticleList',
-  components: { ArticleList },
-  data: function() {
-    return {
-      // wechatType 类型: 1采美,2呵呵商城
-      wechatType: 2
-    }
-  }
-}
-</script>
+<template>
+  <article-list :list-type="wechatType" />
+</template>
+<script>
+import ArticleList from '../../components/articleList'
+export default {
+  name: 'WeChatHeArticleList',
+  components: { ArticleList },
+  data: function() {
+    return {
+      // wechatType 类型: 1采美,2呵呵商城
+      wechatType: 2
+    }
+  }
+}
+</script>

+ 13 - 13
src/views/wechat/hehe/menus/form.vue

@@ -1,13 +1,13 @@
-<template>
-  <menus-form />
-</template>
-<script>
-import MenusForm from '../../components/menusForm'
-export default {
-  name: 'WeChatHeMenuEdit',
-  components: { MenusForm }
-}
-</script>
-<style>
-
-</style>
+<template>
+  <menus-form />
+</template>
+<script>
+import MenusForm from '../../components/menusForm'
+export default {
+  name: 'WeChatHeMenuEdit',
+  components: { MenusForm }
+}
+</script>
+<style>
+
+</style>

+ 16 - 16
src/views/wechat/hehe/menus/list.vue

@@ -1,16 +1,16 @@
-<template>
-  <menus-list :list-type="wechatType" />
-</template>
-<script>
-import MenusList from '../../components/menusList'
-export default {
-  name: 'WeChatHeMenuList',
-  components: { MenusList },
-  data: function() {
-    return {
-      // wechatType 类型: 1采美,2呵呵商城
-      wechatType: 2
-    }
-  }
-}
-</script>
+<template>
+  <menus-list :list-type="wechatType" />
+</template>
+<script>
+import MenusList from '../../components/menusList'
+export default {
+  name: 'WeChatHeMenuList',
+  components: { MenusList },
+  data: function() {
+    return {
+      // wechatType 类型: 1采美,2呵呵商城
+      wechatType: 2
+    }
+  }
+}
+</script>

+ 16 - 16
src/views/wechat/hehe/reply/form.vue

@@ -1,16 +1,16 @@
-<template>
-  <reply-form :type="wechatType" />
-</template>
-<script>
-import ReplyForm from '../../components/replyForm'
-export default {
-  name: 'WeChatHeReplyEdit',
-  components: { ReplyForm },
-  data: function() {
-    return {
-      // wechatType 类型: 1采美,2呵呵商城
-      wechatType: 2
-    }
-  }
-}
-</script>
+<template>
+  <reply-form :type="wechatType" />
+</template>
+<script>
+import ReplyForm from '../../components/replyForm'
+export default {
+  name: 'WeChatHeReplyEdit',
+  components: { ReplyForm },
+  data: function() {
+    return {
+      // wechatType 类型: 1采美,2呵呵商城
+      wechatType: 2
+    }
+  }
+}
+</script>

+ 16 - 16
src/views/wechat/hehe/reply/list.vue

@@ -1,16 +1,16 @@
-<template>
-  <reply-list :list-type="wechatType" />
-</template>
-<script>
-import ReplyList from '../../components/replyList'
-export default {
-  name: 'WeChatHeReplyList',
-  components: { ReplyList },
-  data: function() {
-    return {
-      // wechatType 类型: 1采美,2呵呵商城
-      wechatType: 2
-    }
-  }
-}
-</script>
+<template>
+  <reply-list :list-type="wechatType" />
+</template>
+<script>
+import ReplyList from '../../components/replyList'
+export default {
+  name: 'WeChatHeReplyList',
+  components: { ReplyList },
+  data: function() {
+    return {
+      // wechatType 类型: 1采美,2呵呵商城
+      wechatType: 2
+    }
+  }
+}
+</script>

+ 16 - 16
src/views/wechat/hehe/text/form.vue

@@ -1,16 +1,16 @@
-<template>
-  <text-form :type="wechatType" />
-</template>
-<script>
-import TextForm from '../../components/textForm'
-export default {
-  name: 'WeChatHeTextEdit',
-  components: { TextForm },
-  data: function() {
-    return {
-      // wechatType 类型: 1采美,2呵呵商城
-      wechatType: 2
-    }
-  }
-}
-</script>
+<template>
+  <text-form :type="wechatType" />
+</template>
+<script>
+import TextForm from '../../components/textForm'
+export default {
+  name: 'WeChatHeTextEdit',
+  components: { TextForm },
+  data: function() {
+    return {
+      // wechatType 类型: 1采美,2呵呵商城
+      wechatType: 2
+    }
+  }
+}
+</script>

+ 16 - 16
src/views/wechat/hehe/text/list.vue

@@ -1,16 +1,16 @@
-<template>
-  <text-list :list-type="wechatType" />
-</template>
-<script>
-import TextList from '../../components/textList'
-export default {
-  name: 'WeChatHeTextList',
-  components: { TextList },
-  data: function() {
-    return {
-      // wechatType 类型: 1采美,2呵呵商城
-      wechatType: 2
-    }
-  }
-}
-</script>
+<template>
+  <text-list :list-type="wechatType" />
+</template>
+<script>
+import TextList from '../../components/textList'
+export default {
+  name: 'WeChatHeTextList',
+  components: { TextList },
+  data: function() {
+    return {
+      // wechatType 类型: 1采美,2呵呵商城
+      wechatType: 2
+    }
+  }
+}
+</script>

+ 11 - 11
tailwind.config.js

@@ -1,11 +1,11 @@
-module.exports = {
-  purge: ['./src/**/*.html', './src/**/*.vue'],
-  darkMode: false, // or 'media' or 'class'
-  theme: {
-    extend: {}
-  },
-  variants: {
-    extend: {}
-  },
-  plugins: []
-}
+module.exports = {
+  purge: ['./src/**/*.html', './src/**/*.vue'],
+  darkMode: false, // or 'media' or 'class'
+  theme: {
+    extend: {}
+  },
+  variants: {
+    extend: {}
+  },
+  plugins: []
+}

+ 5 - 5
tests/unit/.eslintrc.js

@@ -1,5 +1,5 @@
-module.exports = {
-  env: {
-    jest: true
-  }
-}
+module.exports = {
+  env: {
+    jest: true
+  }
+}

+ 18 - 18
tests/unit/components/Hamburger.spec.js

@@ -1,18 +1,18 @@
-import { shallowMount } from '@vue/test-utils'
-import Hamburger from '@/components/Hamburger/index.vue'
-describe('Hamburger.vue', () => {
-  it('toggle click', () => {
-    const wrapper = shallowMount(Hamburger)
-    const mockFn = jest.fn()
-    wrapper.vm.$on('toggleClick', mockFn)
-    wrapper.find('.hamburger').trigger('click')
-    expect(mockFn).toBeCalled()
-  })
-  it('prop isActive', () => {
-    const wrapper = shallowMount(Hamburger)
-    wrapper.setProps({ isActive: true })
-    expect(wrapper.contains('.is-active')).toBe(true)
-    wrapper.setProps({ isActive: false })
-    expect(wrapper.contains('.is-active')).toBe(false)
-  })
-})
+import { shallowMount } from '@vue/test-utils'
+import Hamburger from '@/components/Hamburger/index.vue'
+describe('Hamburger.vue', () => {
+  it('toggle click', () => {
+    const wrapper = shallowMount(Hamburger)
+    const mockFn = jest.fn()
+    wrapper.vm.$on('toggleClick', mockFn)
+    wrapper.find('.hamburger').trigger('click')
+    expect(mockFn).toBeCalled()
+  })
+  it('prop isActive', () => {
+    const wrapper = shallowMount(Hamburger)
+    wrapper.setProps({ isActive: true })
+    expect(wrapper.contains('.is-active')).toBe(true)
+    wrapper.setProps({ isActive: false })
+    expect(wrapper.contains('.is-active')).toBe(false)
+  })
+})

+ 22 - 22
tests/unit/components/SvgIcon.spec.js

@@ -1,22 +1,22 @@
-import { shallowMount } from '@vue/test-utils'
-import SvgIcon from '@/components/SvgIcon/index.vue'
-describe('SvgIcon.vue', () => {
-  it('iconClass', () => {
-    const wrapper = shallowMount(SvgIcon, {
-      propsData: {
-        iconClass: 'test'
-      }
-    })
-    expect(wrapper.find('use').attributes().href).toBe('#icon-test')
-  })
-  it('className', () => {
-    const wrapper = shallowMount(SvgIcon, {
-      propsData: {
-        iconClass: 'test'
-      }
-    })
-    expect(wrapper.classes().length).toBe(1)
-    wrapper.setProps({ className: 'test' })
-    expect(wrapper.classes().includes('test')).toBe(true)
-  })
-})
+import { shallowMount } from '@vue/test-utils'
+import SvgIcon from '@/components/SvgIcon/index.vue'
+describe('SvgIcon.vue', () => {
+  it('iconClass', () => {
+    const wrapper = shallowMount(SvgIcon, {
+      propsData: {
+        iconClass: 'test'
+      }
+    })
+    expect(wrapper.find('use').attributes().href).toBe('#icon-test')
+  })
+  it('className', () => {
+    const wrapper = shallowMount(SvgIcon, {
+      propsData: {
+        iconClass: 'test'
+      }
+    })
+    expect(wrapper.classes().length).toBe(1)
+    wrapper.setProps({ className: 'test' })
+    expect(wrapper.classes().includes('test')).toBe(true)
+  })
+})

+ 29 - 29
tests/unit/utils/formatTime.spec.js

@@ -1,29 +1,29 @@
-import { formatTime } from '@/utils/index.js'
-describe('Utils:formatTime', () => {
-  const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
-  const retrofit = 5 * 1000
-
-  it('ten digits timestamp', () => {
-    expect(formatTime((d / 1000).toFixed(0))).toBe('7月13日17时54分')
-  })
-  it('test now', () => {
-    expect(formatTime(+new Date() - 1)).toBe('刚刚')
-  })
-  it('less two minute', () => {
-    expect(formatTime(+new Date() - 60 * 2 * 1000 + retrofit)).toBe('2分钟前')
-  })
-  it('less two hour', () => {
-    expect(formatTime(+new Date() - 60 * 60 * 2 * 1000 + retrofit)).toBe('2小时前')
-  })
-  it('less one day', () => {
-    expect(formatTime(+new Date() - 60 * 60 * 24 * 1 * 1000)).toBe('1天前')
-  })
-  it('more than one day', () => {
-    expect(formatTime(d)).toBe('7月13日17时54分')
-  })
-  it('format', () => {
-    expect(formatTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
-    expect(formatTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
-    expect(formatTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
-  })
-})
+import { formatTime } from '@/utils/index.js'
+describe('Utils:formatTime', () => {
+  const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
+  const retrofit = 5 * 1000
+
+  it('ten digits timestamp', () => {
+    expect(formatTime((d / 1000).toFixed(0))).toBe('7月13日17时54分')
+  })
+  it('test now', () => {
+    expect(formatTime(+new Date() - 1)).toBe('刚刚')
+  })
+  it('less two minute', () => {
+    expect(formatTime(+new Date() - 60 * 2 * 1000 + retrofit)).toBe('2分钟前')
+  })
+  it('less two hour', () => {
+    expect(formatTime(+new Date() - 60 * 60 * 2 * 1000 + retrofit)).toBe('2小时前')
+  })
+  it('less one day', () => {
+    expect(formatTime(+new Date() - 60 * 60 * 24 * 1 * 1000)).toBe('1天前')
+  })
+  it('more than one day', () => {
+    expect(formatTime(d)).toBe('7月13日17时54分')
+  })
+  it('format', () => {
+    expect(formatTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
+    expect(formatTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
+    expect(formatTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
+  })
+})

+ 14 - 14
tests/unit/utils/param2Obj.spec.js

@@ -1,14 +1,14 @@
-import { param2Obj } from '@/utils/index.js'
-describe('Utils:param2Obj', () => {
-  const url = 'https://github.com/PanJiaChen/vue-element-admin?name=bill&age=29&sex=1&field=dGVzdA==&key=%E6%B5%8B%E8%AF%95'
-
-  it('param2Obj test', () => {
-    expect(param2Obj(url)).toEqual({
-      name: 'bill',
-      age: '29',
-      sex: '1',
-      field: window.btoa('test'),
-      key: '测试'
-    })
-  })
-})
+import { param2Obj } from '@/utils/index.js'
+describe('Utils:param2Obj', () => {
+  const url = 'https://github.com/PanJiaChen/vue-element-admin?name=bill&age=29&sex=1&field=dGVzdA==&key=%E6%B5%8B%E8%AF%95'
+
+  it('param2Obj test', () => {
+    expect(param2Obj(url)).toEqual({
+      name: 'bill',
+      age: '29',
+      sex: '1',
+      field: window.btoa('test'),
+      key: '测试'
+    })
+  })
+})

+ 37 - 37
tests/unit/utils/parseTime.spec.js

@@ -1,37 +1,37 @@
-import { parseTime } from '@/utils/index.js'
-
-describe('Utils:parseTime', () => {
-  const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
-  it('timestamp', () => {
-    expect(parseTime(d)).toBe('2018-07-13 17:54:01')
-  })
-
-  it('timestamp string', () => {
-    expect(parseTime((d + ''))).toBe('2018-07-13 17:54:01')
-  })
-
-  it('ten digits timestamp', () => {
-    expect(parseTime((d / 1000).toFixed(0))).toBe('2018-07-13 17:54:01')
-  })
-  it('new Date', () => {
-    expect(parseTime(new Date(d))).toBe('2018-07-13 17:54:01')
-  })
-  it('format', () => {
-    expect(parseTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
-    expect(parseTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
-    expect(parseTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
-  })
-  it('get the day of the week', () => {
-    expect(parseTime(d, '{a}')).toBe('五') // 星期五
-  })
-  it('get the day of the week', () => {
-    expect(parseTime(+d + 1000 * 60 * 60 * 24 * 2, '{a}')).toBe('日') // 星期日
-  })
-  it('empty argument', () => {
-    expect(parseTime()).toBeNull()
-  })
-
-  it('null', () => {
-    expect(parseTime(null)).toBeNull()
-  })
-})
+import { parseTime } from '@/utils/index.js'
+
+describe('Utils:parseTime', () => {
+  const d = new Date('2018-07-13 17:54:01') // "2018-07-13 17:54:01"
+  it('timestamp', () => {
+    expect(parseTime(d)).toBe('2018-07-13 17:54:01')
+  })
+
+  it('timestamp string', () => {
+    expect(parseTime((d + ''))).toBe('2018-07-13 17:54:01')
+  })
+
+  it('ten digits timestamp', () => {
+    expect(parseTime((d / 1000).toFixed(0))).toBe('2018-07-13 17:54:01')
+  })
+  it('new Date', () => {
+    expect(parseTime(new Date(d))).toBe('2018-07-13 17:54:01')
+  })
+  it('format', () => {
+    expect(parseTime(d, '{y}-{m}-{d} {h}:{i}')).toBe('2018-07-13 17:54')
+    expect(parseTime(d, '{y}-{m}-{d}')).toBe('2018-07-13')
+    expect(parseTime(d, '{y}/{m}/{d} {h}-{i}')).toBe('2018/07/13 17-54')
+  })
+  it('get the day of the week', () => {
+    expect(parseTime(d, '{a}')).toBe('五') // 星期五
+  })
+  it('get the day of the week', () => {
+    expect(parseTime(+d + 1000 * 60 * 60 * 24 * 2, '{a}')).toBe('日') // 星期日
+  })
+  it('empty argument', () => {
+    expect(parseTime()).toBeNull()
+  })
+
+  it('null', () => {
+    expect(parseTime(null)).toBeNull()
+  })
+})

+ 28 - 28
tests/unit/utils/validate.spec.js

@@ -1,28 +1,28 @@
-import { validUsername, validURL, validLowerCase, validUpperCase, validAlphabets } from '@/utils/validate.js'
-describe('Utils:validate', () => {
-  it('validUsername', () => {
-    expect(validUsername('admin')).toBe(true)
-    expect(validUsername('editor')).toBe(true)
-    expect(validUsername('xxxx')).toBe(false)
-  })
-  it('validURL', () => {
-    expect(validURL('https://github.com/PanJiaChen/vue-element-admin')).toBe(true)
-    expect(validURL('http://github.com/PanJiaChen/vue-element-admin')).toBe(true)
-    expect(validURL('github.com/PanJiaChen/vue-element-admin')).toBe(false)
-  })
-  it('validLowerCase', () => {
-    expect(validLowerCase('abc')).toBe(true)
-    expect(validLowerCase('Abc')).toBe(false)
-    expect(validLowerCase('123abc')).toBe(false)
-  })
-  it('validUpperCase', () => {
-    expect(validUpperCase('ABC')).toBe(true)
-    expect(validUpperCase('Abc')).toBe(false)
-    expect(validUpperCase('123ABC')).toBe(false)
-  })
-  it('validAlphabets', () => {
-    expect(validAlphabets('ABC')).toBe(true)
-    expect(validAlphabets('Abc')).toBe(true)
-    expect(validAlphabets('123aBC')).toBe(false)
-  })
-})
+import { validUsername, validURL, validLowerCase, validUpperCase, validAlphabets } from '@/utils/validate.js'
+describe('Utils:validate', () => {
+  it('validUsername', () => {
+    expect(validUsername('admin')).toBe(true)
+    expect(validUsername('editor')).toBe(true)
+    expect(validUsername('xxxx')).toBe(false)
+  })
+  it('validURL', () => {
+    expect(validURL('https://github.com/PanJiaChen/vue-element-admin')).toBe(true)
+    expect(validURL('http://github.com/PanJiaChen/vue-element-admin')).toBe(true)
+    expect(validURL('github.com/PanJiaChen/vue-element-admin')).toBe(false)
+  })
+  it('validLowerCase', () => {
+    expect(validLowerCase('abc')).toBe(true)
+    expect(validLowerCase('Abc')).toBe(false)
+    expect(validLowerCase('123abc')).toBe(false)
+  })
+  it('validUpperCase', () => {
+    expect(validUpperCase('ABC')).toBe(true)
+    expect(validUpperCase('Abc')).toBe(false)
+    expect(validUpperCase('123ABC')).toBe(false)
+  })
+  it('validAlphabets', () => {
+    expect(validAlphabets('ABC')).toBe(true)
+    expect(validAlphabets('Abc')).toBe(true)
+    expect(validAlphabets('123aBC')).toBe(false)
+  })
+})

+ 124 - 124
vue.config.js

@@ -1,124 +1,124 @@
-'use strict'
-const path = require('path')
-const defaultSettings = require('./src/settings.js')
-
-function resolve(dir) {
-  return path.join(__dirname, dir)
-}
-
-const name = defaultSettings.title || '采美后台' // page title
-
-// If your port is set to 80,
-// use administrator privileges to execute the command line.
-// For example, Mac: sudo npm run
-// You can change the port by the following method:
-// port = 9527 npm run dev OR npm run dev --port = 9527
-const port = process.env.port || process.env.npm_config_port || 9527 // dev port
-
-// All configuration item explanations can be find in https://cli.vuejs.org/config/
-module.exports = {
-  /**
-   * You will need to set publicPath if you plan to deploy your site under a sub path,
-   * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
-   * then publicPath should be set to "/bar/".
-   * In most cases please use '/' !!!
-   * Detail: https://cli.vuejs.org/config/#publicpath
-   */
-  publicPath: '/',
-  outputDir: 'dist',
-  assetsDir: 'static',
-  lintOnSave: process.env.NODE_ENV === 'development',
-  productionSourceMap: false,
-  devServer: {
-    port: port,
-    open: true,
-    overlay: {
-      warnings: false,
-      errors: true
-    }
-    // before: require('./mock/mock-server.js')
-  },
-  configureWebpack: {
-    // provide the app's title in webpack's name field, so that
-    // it can be accessed in index.html to inject the correct title.
-    name: name,
-    resolve: {
-      alias: {
-        '@': resolve('src')
-      }
-    }
-  },
-  chainWebpack(config) {
-    // it can improve the speed of the first screen, it is recommended to turn on preload
-    // it can improve the speed of the first screen, it is recommended to turn on preload
-    config.plugin('preload').tap(() => [
-      {
-        rel: 'preload',
-        // to ignore runtime.js
-        // https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
-        fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
-        include: 'initial'
-      }
-    ])
-
-    // when there are many pages, it will cause too many meaningless requests
-    config.plugins.delete('prefetch')
-
-    // set svg-sprite-loader
-    config.module
-      .rule('svg')
-      .exclude.add(resolve('src/icons'))
-      .end()
-    config.module
-      .rule('icons')
-      .test(/\.svg$/)
-      .include.add(resolve('src/icons'))
-      .end()
-      .use('svg-sprite-loader')
-      .loader('svg-sprite-loader')
-      .options({
-        symbolId: 'icon-[name]'
-      })
-      .end()
-
-    config
-      .when(process.env.NODE_ENV !== 'development',
-        config => {
-          config
-            .plugin('ScriptExtHtmlWebpackPlugin')
-            .after('html')
-            .use('script-ext-html-webpack-plugin', [{
-            // `runtime` must same as runtimeChunk name. default is `runtime`
-              inline: /runtime\..*\.js$/
-            }])
-            .end()
-          config
-            .optimization.splitChunks({
-              chunks: 'all',
-              cacheGroups: {
-                libs: {
-                  name: 'chunk-libs',
-                  test: /[\\/]node_modules[\\/]/,
-                  priority: 10,
-                  chunks: 'initial' // only package third parties that are initially dependent
-                },
-                elementUI: {
-                  name: 'chunk-elementUI', // split elementUI into a single package
-                  priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
-                  test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
-                },
-                commons: {
-                  name: 'chunk-commons',
-                  test: resolve('src/components'), // can customize your rules
-                  minChunks: 3, //  minimum common number
-                  priority: 5,
-                  reuseExistingChunk: true
-                }
-              }
-            })
-          // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
-          config.optimization.runtimeChunk('single')
-        }
-      )
-  }
-}
+'use strict'
+const path = require('path')
+const defaultSettings = require('./src/settings.js')
+
+function resolve(dir) {
+  return path.join(__dirname, dir)
+}
+
+const name = defaultSettings.title || '采美后台' // page title
+
+// If your port is set to 80,
+// use administrator privileges to execute the command line.
+// For example, Mac: sudo npm run
+// You can change the port by the following method:
+// port = 9527 npm run dev OR npm run dev --port = 9527
+const port = process.env.port || process.env.npm_config_port || 9527 // dev port
+
+// All configuration item explanations can be find in https://cli.vuejs.org/config/
+module.exports = {
+  /**
+   * You will need to set publicPath if you plan to deploy your site under a sub path,
+   * for example GitHub Pages. If you plan to deploy your site to https://foo.github.io/bar/,
+   * then publicPath should be set to "/bar/".
+   * In most cases please use '/' !!!
+   * Detail: https://cli.vuejs.org/config/#publicpath
+   */
+  publicPath: '/',
+  outputDir: 'dist',
+  assetsDir: 'static',
+  lintOnSave: process.env.NODE_ENV === 'development',
+  productionSourceMap: false,
+  devServer: {
+    port: port,
+    open: true,
+    overlay: {
+      warnings: false,
+      errors: true
+    }
+    // before: require('./mock/mock-server.js')
+  },
+  configureWebpack: {
+    // provide the app's title in webpack's name field, so that
+    // it can be accessed in index.html to inject the correct title.
+    name: name,
+    resolve: {
+      alias: {
+        '@': resolve('src')
+      }
+    }
+  },
+  chainWebpack(config) {
+    // it can improve the speed of the first screen, it is recommended to turn on preload
+    // it can improve the speed of the first screen, it is recommended to turn on preload
+    config.plugin('preload').tap(() => [
+      {
+        rel: 'preload',
+        // to ignore runtime.js
+        // https://github.com/vuejs/vue-cli/blob/dev/packages/@vue/cli-service/lib/config/app.js#L171
+        fileBlacklist: [/\.map$/, /hot-update\.js$/, /runtime\..*\.js$/],
+        include: 'initial'
+      }
+    ])
+
+    // when there are many pages, it will cause too many meaningless requests
+    config.plugins.delete('prefetch')
+
+    // set svg-sprite-loader
+    config.module
+      .rule('svg')
+      .exclude.add(resolve('src/icons'))
+      .end()
+    config.module
+      .rule('icons')
+      .test(/\.svg$/)
+      .include.add(resolve('src/icons'))
+      .end()
+      .use('svg-sprite-loader')
+      .loader('svg-sprite-loader')
+      .options({
+        symbolId: 'icon-[name]'
+      })
+      .end()
+
+    config
+      .when(process.env.NODE_ENV !== 'development',
+        config => {
+          config
+            .plugin('ScriptExtHtmlWebpackPlugin')
+            .after('html')
+            .use('script-ext-html-webpack-plugin', [{
+            // `runtime` must same as runtimeChunk name. default is `runtime`
+              inline: /runtime\..*\.js$/
+            }])
+            .end()
+          config
+            .optimization.splitChunks({
+              chunks: 'all',
+              cacheGroups: {
+                libs: {
+                  name: 'chunk-libs',
+                  test: /[\\/]node_modules[\\/]/,
+                  priority: 10,
+                  chunks: 'initial' // only package third parties that are initially dependent
+                },
+                elementUI: {
+                  name: 'chunk-elementUI', // split elementUI into a single package
+                  priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
+                  test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
+                },
+                commons: {
+                  name: 'chunk-commons',
+                  test: resolve('src/components'), // can customize your rules
+                  minChunks: 3, //  minimum common number
+                  priority: 5,
+                  reuseExistingChunk: true
+                }
+              }
+            })
+          // https:// webpack.js.org/configuration/optimization/#optimizationruntimechunk
+          config.optimization.runtimeChunk('single')
+        }
+      )
+  }
+}