zjxpcyc 6 lat temu
commit
a51e59aac6

+ 21
- 0
.gitignore Wyświetl plik

@@ -0,0 +1,21 @@
1
+.DS_Store
2
+node_modules
3
+/dist
4
+
5
+# local env files
6
+.env.local
7
+.env.*.local
8
+
9
+# Log files
10
+npm-debug.log*
11
+yarn-debug.log*
12
+yarn-error.log*
13
+
14
+# Editor directories and files
15
+.idea
16
+.vscode
17
+*.suo
18
+*.ntvs*
19
+*.njsproj
20
+*.sln
21
+*.sw*

+ 26
- 0
README.md Wyświetl plik

@@ -0,0 +1,26 @@
1
+# annual-lottery
2
+
3
+## Project setup
4
+```
5
+npm install
6
+```
7
+
8
+### Compiles and hot-reloads for development
9
+```
10
+npm run serve
11
+```
12
+
13
+### Compiles and minifies for production
14
+```
15
+npm run build
16
+```
17
+
18
+### Run your tests
19
+```
20
+npm run test
21
+```
22
+
23
+### Lints and fixes files
24
+```
25
+npm run lint
26
+```

+ 5
- 0
babel.config.js Wyświetl plik

@@ -0,0 +1,5 @@
1
+module.exports = {
2
+  presets: [
3
+    '@vue/app'
4
+  ]
5
+}

+ 10954
- 0
package-lock.json
Plik diff jest za duży
Wyświetl plik


+ 49
- 0
package.json Wyświetl plik

@@ -0,0 +1,49 @@
1
+{
2
+  "name": "annual-lottery",
3
+  "version": "0.1.0",
4
+  "private": true,
5
+  "scripts": {
6
+    "serve": "vue-cli-service serve",
7
+    "build": "vue-cli-service build",
8
+    "lint": "vue-cli-service lint"
9
+  },
10
+  "dependencies": {
11
+    "axios": "^0.18.0",
12
+    "element-ui": "^2.4.11",
13
+    "vue": "^2.5.21",
14
+    "vue-router": "^3.0.2"
15
+  },
16
+  "devDependencies": {
17
+    "@vue/cli-plugin-babel": "^3.0.5",
18
+    "@vue/cli-plugin-eslint": "^3.0.5",
19
+    "@vue/cli-service": "^3.0.5",
20
+    "babel-eslint": "^10.0.1",
21
+    "eslint": "^5.8.0",
22
+    "eslint-plugin-vue": "^5.0.0",
23
+    "vue-template-compiler": "^2.5.21"
24
+  },
25
+  "eslintConfig": {
26
+    "root": true,
27
+    "env": {
28
+      "node": true
29
+    },
30
+    "extends": [
31
+      "plugin:vue/essential",
32
+      "eslint:recommended"
33
+    ],
34
+    "rules": {},
35
+    "parserOptions": {
36
+      "parser": "babel-eslint"
37
+    }
38
+  },
39
+  "postcss": {
40
+    "plugins": {
41
+      "autoprefixer": {}
42
+    }
43
+  },
44
+  "browserslist": [
45
+    "> 1%",
46
+    "last 2 versions",
47
+    "not ie <= 8"
48
+  ]
49
+}

BIN
public/favicon.ico Wyświetl plik


+ 17
- 0
public/index.html Wyświetl plik

@@ -0,0 +1,17 @@
1
+<!DOCTYPE html>
2
+<html lang="en">
3
+  <head>
4
+    <meta charset="utf-8">
5
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
6
+    <meta name="viewport" content="width=device-width,initial-scale=1.0">
7
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
8
+    <title>annual-lottery</title>
9
+  </head>
10
+  <body>
11
+    <noscript>
12
+      <strong>We're sorry but annual-lottery doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
13
+    </noscript>
14
+    <div id="app"></div>
15
+    <!-- built files will be auto injected -->
16
+  </body>
17
+</html>

+ 23
- 0
src/App.vue Wyświetl plik

@@ -0,0 +1,23 @@
1
+<template>
2
+  <div id="app">
3
+    <router-view></router-view>
4
+  </div>
5
+</template>
6
+<script>
7
+
8
+export default {
9
+  name: 'app',
10
+}
11
+</script>
12
+
13
+<style>
14
+  html, body, #app {
15
+    margin: 0;
16
+    height: 100%;
17
+  }
18
+
19
+  #app {
20
+    background-color: #fafafa;
21
+  }
22
+</style>
23
+

+ 75
- 0
src/apis.js Wyświetl plik

@@ -0,0 +1,75 @@
1
+import { replaceUrlParams, objectGet } from './utils'
2
+
3
+const prefix = '/api'
4
+const apis = {
5
+  // 参与人员
6
+  user: {
7
+    list: {
8
+      url: `${prefix}/user`,
9
+      method: 'get',
10
+    }
11
+  },
12
+  // 设置
13
+  setting: {
14
+    // 抽奖设置
15
+    prize: {
16
+      list: {
17
+        url: `${prefix}/setting/prize`,
18
+        method: 'get',
19
+      },
20
+      save: {
21
+        url: `${prefix}/setting/prize`,
22
+        method: 'post',
23
+      }
24
+    }
25
+  },
26
+  // 抽奖
27
+  draw: {
28
+    url: `${prefix}/draw`,
29
+    method: 'post',
30
+  },
31
+  // 奖品维护
32
+  prize: {
33
+    list: {
34
+      url: `${prefix}/prize`,
35
+      method: 'get',
36
+    },
37
+    save: {
38
+      url: `${prefix}/prize`,
39
+      method: 'post',
40
+    },
41
+    update: {
42
+      url: `${prefix}/prize/:PrizeId`,
43
+      method: 'put',
44
+    }
45
+  },
46
+  // 中奖名单
47
+  winner: {
48
+    list: {
49
+      url: `${prefix}/winner`,
50
+      method: 'get',
51
+    },
52
+    // 取消中奖
53
+    cancel: {
54
+      url: `${prefix}/winner/:UserId`,
55
+      method: 'delete',
56
+    }
57
+  },
58
+  // excel 导出
59
+  excel: {
60
+    winner: {
61
+      url: `${prefix}/excel/winner`,
62
+      method: 'get',
63
+    }
64
+  }
65
+}
66
+
67
+
68
+// getApi
69
+// name is the key, but also can be a.b
70
+// urlparams is option
71
+export default function getApi(name, urlparams) {
72
+  const api = objectGet(apis, name)
73
+  const url = replaceUrlParams(api.url, urlparams)
74
+  return { ...api, url }
75
+}

BIN
src/assets/logo.png Wyświetl plik


+ 80
- 0
src/components/prize.vue Wyświetl plik

@@ -0,0 +1,80 @@
1
+<template>
2
+  <div>
3
+    <div style="margin-bottom: 20px">
4
+      <el-button @click="dialogVisible = true">新增</el-button>
5
+    </div>
6
+    <el-table
7
+      :data="data"
8
+      highlight-current-row
9
+      border
10
+      style="width: 100%">
11
+      <el-table-column
12
+        prop="PrizeName"
13
+        label="奖品">
14
+      </el-table-column>
15
+      <el-table-column
16
+        prop="PrizeType"
17
+        label="类型">
18
+      </el-table-column>
19
+      <el-table-column
20
+        prop="Stock"
21
+        label="数量">
22
+      </el-table-column>
23
+      <el-table-column
24
+        prop="Picture"
25
+        label="图片">
26
+      </el-table-column>
27
+    </el-table>
28
+    <el-dialog
29
+      title="提示"
30
+      :visible.sync="dialogVisible"
31
+      width="60%">
32
+      <el-form label-width="120px" :model="formData">
33
+        <el-form-item label="名称">
34
+          <el-input v-model="formData.PrizeName"></el-input>
35
+        </el-form-item>
36
+        <el-form-item label="类型">
37
+          <el-input v-model="formData.PrizeType" placeholder="一等奖, 二等奖"></el-input>
38
+        </el-form-item>
39
+        <el-form-item label="数量">
40
+          <el-input-number v-model="formData.Stock" :min="1"></el-input-number>
41
+        </el-form-item>
42
+        <el-form-item label="图片">
43
+        </el-form-item>
44
+        <el-form-item>
45
+          <el-button type="primary" @click="onSubmit">确定</el-button>
46
+        </el-form-item>
47
+      </el-form>
48
+    </el-dialog>
49
+  </div>
50
+</template>
51
+
52
+<script>
53
+export default {
54
+  name: 'setting',
55
+  props: [
56
+    'data',
57
+  ],
58
+  data() {
59
+    return {
60
+      dialogVisible: false,
61
+      formData: {
62
+        PrizeId: 0,
63
+        PrizeType: '',
64
+        PrizeName: '',
65
+        Picture: '',
66
+        Stock: 1,
67
+      },
68
+    }
69
+  },
70
+  methods: {
71
+    onSubmit() {
72
+      this.$emit('submit', { ...this.formData })
73
+      this.dialogVisible = false
74
+    }
75
+  }
76
+}
77
+</script>
78
+
79
+<style>
80
+</style>

+ 113
- 0
src/components/setting.vue Wyświetl plik

@@ -0,0 +1,113 @@
1
+<template>
2
+  <div>
3
+    <div style="margin-bottom: 20px">
4
+      <el-button @click="dialogVisible = true">新增</el-button>
5
+    </div>
6
+    <el-table
7
+      :data="data"
8
+      highlight-current-row
9
+      border
10
+      style="width: 100%"
11
+      :row-class-name="activeRow">
12
+      <el-table-column
13
+        prop="SettingId"
14
+        label="ID"
15
+        width="100">
16
+      </el-table-column>
17
+      <el-table-column
18
+        prop="PrizeId"
19
+        label="奖品"
20
+        :formatter="showPrizeName"
21
+        >
22
+      </el-table-column>
23
+      <el-table-column
24
+        prop="PrizeNum"
25
+        label="数量"
26
+        width="100">
27
+      </el-table-column>
28
+      <el-table-column
29
+        prop="IsRepeat"
30
+        label="允许重复抽"
31
+        :formatter="showRepeat"
32
+        width="150">
33
+      </el-table-column>
34
+      <el-table-column
35
+        prop="Status"
36
+        label="状态"
37
+        :formatter="showStatus"
38
+        width="150">
39
+      </el-table-column>
40
+    </el-table>
41
+    <el-dialog
42
+      title="提示"
43
+      :visible.sync="dialogVisible"
44
+      width="60%">
45
+      <el-form label-width="120px" :model="formData">
46
+        <el-form-item label="奖品">
47
+          <el-select v-model="formData.PrizeId">
48
+            <el-option v-for="item in prizes" :key="item.PrizeId" :label="`${item.PrizeType} - ${item.PrizeName}`" :value="item.PrizeId"></el-option>
49
+          </el-select>
50
+        </el-form-item>
51
+        <el-form-item label="数量">
52
+          <el-input-number v-model="formData.PrizeNum" :min="1"></el-input-number>
53
+        </el-form-item>
54
+        <el-form-item label="允许重复抽">
55
+          <el-select v-model="formData.IsRepeat">
56
+            <el-option label="是" value="1"></el-option>
57
+            <el-option label="否" value="0"></el-option>
58
+          </el-select>
59
+        </el-form-item>
60
+        <el-form-item>
61
+          <el-button type="primary" @click="onSubmit">确定</el-button>
62
+        </el-form-item>
63
+      </el-form>
64
+    </el-dialog>
65
+  </div>
66
+</template>
67
+
68
+<script>
69
+export default {
70
+  name: 'setting',
71
+  props: [
72
+    'data',
73
+    'prizes',
74
+  ],
75
+  data() {
76
+    return {
77
+      dialogVisible: false,
78
+      formData: {
79
+        PrizeId: undefined,
80
+        IsRepeat: '0',
81
+        PrizeNum: 1,
82
+      },
83
+    }
84
+  },
85
+  methods: {
86
+    activeRow({ row }) {
87
+      if (row.Status === 1) {
88
+        return 'tab-row-active'
89
+      }
90
+    },
91
+    showPrizeName(row, col, val) {
92
+      const prize = (this.prizes || []).filter(({ PrizeId: x }) => x === val)[0] || {}
93
+      return `${prize.PrizeType} - ${prize.PrizeName}`;
94
+    },
95
+    showRepeat(row, col, val) {
96
+      return val === 1 ? '允许' : '不允许'
97
+    },
98
+    showStatus(row, col, val) {
99
+      return val === 1 ? '有效' : '已抽过'
100
+    },
101
+    onSubmit() {
102
+      this.$emit('submit', { ...this.formData, IsRepeat: this.formData.IsRepeat - 0 })
103
+      this.dialogVisible = false
104
+    }
105
+  }
106
+}
107
+</script>
108
+
109
+<style>
110
+.el-table .tab-row-active {
111
+    background: #f0f9eb;
112
+  }
113
+</style>

+ 142
- 0
src/components/winner.vue Wyświetl plik

@@ -0,0 +1,142 @@
1
+<template>
2
+  <div>
3
+    <div :style="{ margin: '20px 0' }">
4
+      <el-form :inline="true" :model="formData">
5
+        <el-form-item label="中奖人">
6
+          <el-input v-model="formData.name"></el-input>
7
+        </el-form-item>
8
+        <el-form-item label="奖品等级">
9
+          <el-input v-model="formData.type" placeholder="一等奖, 二等奖 ..."></el-input>
10
+        </el-form-item>
11
+        <el-form-item>
12
+          <el-button type="primary" @click="onSearch">查询</el-button>
13
+          <el-button type="text" @click="exportExcel()" :style="{ marginLeft: '40px' }">导出所有</el-button>
14
+        </el-form-item>
15
+      </el-form>
16
+    </div>
17
+    <el-table
18
+      :data="tableData"
19
+      highlight-current-row
20
+      border
21
+      style="width: 100%">
22
+      <el-table-column type="expand">
23
+        <template slot-scope="props">
24
+          <el-table :data="props.row.winners" size="small" border :row-class-name="errorRow">
25
+            <el-table-column
26
+                prop="UserName"
27
+                label="名称">
28
+              </el-table-column>
29
+              <el-table-column
30
+                prop="UserOrg"
31
+                label="组织">
32
+              </el-table-column>
33
+              <el-table-column
34
+                prop="UserDept"
35
+                label="部门">
36
+              </el-table-column>
37
+              <el-table-column
38
+                prop="Status"
39
+                label="状态"
40
+                :formatter="showStatus">
41
+              </el-table-column>
42
+              <el-table-column
43
+                fixed="right"
44
+                label="操作"
45
+                width="150">
46
+                <template slot-scope="scope">
47
+                  <el-button v-if="scope.row.Status === 1" @click="cancelWinner(scope.row)" type="text">取消</el-button>
48
+                </template>
49
+              </el-table-column>
50
+          </el-table>
51
+        </template>
52
+      </el-table-column>
53
+      <el-table-column
54
+        prop="PrizeType"
55
+        label="奖类">
56
+      </el-table-column>
57
+      <el-table-column
58
+        prop="PrizeName"
59
+        label="奖品">
60
+      </el-table-column>
61
+      <el-table-column
62
+        fixed="right"
63
+        label="操作"
64
+        width="150">
65
+        <template slot-scope="scope">
66
+          <el-button @click="exportExcel(scope.row)" type="text" >导出</el-button>
67
+        </template>
68
+      </el-table-column>
69
+    </el-table>
70
+  </div>
71
+</template>
72
+
73
+<script>
74
+import { groupBy } from '../utils'
75
+
76
+export default {
77
+  name: 'winner',
78
+  props: [
79
+    'data',
80
+    'prizes'
81
+  ],
82
+  data() {
83
+    return {
84
+      formData: {
85
+        name: '',
86
+        type: '',
87
+      },
88
+    }
89
+  },
90
+  computed: {
91
+    tableData() {
92
+      const gdata = groupBy(this.data, 'PrizeId')
93
+
94
+      return Object.keys(gdata).map((k) => {
95
+        const prize = (this.prizes || []).filter(x => x.PrizeId == k)[0] || {}
96
+
97
+        return {
98
+          ...prize,
99
+          winners: gdata[k]
100
+        }
101
+      })
102
+    }
103
+  },
104
+  methods: {
105
+    onSearch() {
106
+      this.$emit('search', this.formData)
107
+    },
108
+    cancelWinner(row) {
109
+      this.$confirm('确认要取消该人员中奖资格?', '提示', {
110
+          confirmButtonText: '确定',
111
+          cancelButtonText: '取消',
112
+          type: 'warning'
113
+        }).then(() => {
114
+          this.$emit('cancel', row)
115
+        })      
116
+    },
117
+    errorRow({ row }) {
118
+      if (row.Status === -1) {
119
+        return 'tab-row-error'
120
+      }
121
+    },
122
+    showStatus(row, col, val) {
123
+      return val === 1 ? '有效' : '被取消'
124
+    },
125
+    exportExcel(row) {
126
+      // 导出全部
127
+      if (!row) {
128
+        this.$emit("exportExcel")
129
+        return
130
+      }
131
+
132
+      this.$emit("exportExcel", { type: row.PrizeType })
133
+    },
134
+  }
135
+}
136
+</script>
137
+
138
+<style>
139
+.el-table .tab-row-error {
140
+    background-color: #fef0f0;
141
+  }
142
+</style>

+ 15
- 0
src/main.js Wyświetl plik

@@ -0,0 +1,15 @@
1
+import Vue from 'vue'
2
+import VueRouter from 'vue-router'
3
+import ElementUI from 'element-ui'
4
+import 'element-ui/lib/theme-chalk/index.css'
5
+import App from './App.vue'
6
+import router from './router'
7
+
8
+Vue.use(VueRouter)
9
+Vue.use(ElementUI)
10
+Vue.config.productionTip = false
11
+
12
+new Vue({
13
+  router,
14
+  render: h => h(App),
15
+}).$mount('#app')

+ 137
- 0
src/pages/admin.vue Wyświetl plik

@@ -0,0 +1,137 @@
1
+<template>
2
+  <el-container>
3
+    <el-header>
4
+      <el-row :gutter="20">
5
+        <el-col :span="6">
6
+          <div class="logo">抽奖系统</div>
7
+        </el-col>
8
+        <el-col :span="18"></el-col>
9
+      </el-row>
10
+    </el-header>
11
+    <el-main>
12
+      <el-tabs v-model="activeTab" type="card" @tab-click="tabChange">
13
+        <el-tab-pane label="抽奖配置" name="setting">
14
+          <prize-setting :data="settings" :prizes="prizes" @submit="saveSetting"></prize-setting>
15
+        </el-tab-pane>
16
+        <el-tab-pane label="中奖名单" name="winner">
17
+          <winner :data="winners" :prizes="prizes" @search="searchWinner" @cancel="cancelWinner" @exportExcel="exportExcel"></winner>
18
+        </el-tab-pane>
19
+        <el-tab-pane label="奖品管理" name="prize">
20
+          <prize :data="prizes" @submit="savePrize"></prize>
21
+        </el-tab-pane>
22
+      </el-tabs>
23
+    </el-main>
24
+  </el-container>
25
+</template>
26
+
27
+<script>
28
+import getApi from '../apis.js'
29
+import request from '../utils/request.js'
30
+
31
+export default {
32
+  name: 'admin-board',
33
+  components: {
34
+    'prize-setting': () => import('../components/setting.vue'),
35
+    'winner': () => import('../components/winner.vue'),
36
+    'prize': () => import('../components/prize.vue')
37
+  },
38
+  created() {
39
+    this.getSettingList()
40
+    this.getPrizeList()
41
+  },
42
+  data() {
43
+    return {
44
+      activeTab: 'setting',
45
+
46
+      // 人员列表
47
+      users: [],
48
+      // 中奖名单
49
+      winners: [],
50
+      // 奖品列表
51
+      prizes: [],
52
+      // 抽奖配置
53
+      settings: [],
54
+    }
55
+  },
56
+  methods: {
57
+    tabChange(tab) {
58
+      switch (tab.name) {
59
+        case 'winner':
60
+          this.getWinnerList()
61
+          break;
62
+        case 'prize':
63
+          this.getPrizeList()
64
+          break;
65
+      }
66
+    },
67
+    getSettingList() {
68
+      const api = getApi('setting.prize.list')
69
+      request(api).then(({ settings }) => {
70
+        this.settings = settings
71
+      })
72
+    },
73
+    saveSetting(data) {
74
+      const api = getApi('setting.prize.save')
75
+      request({ ...api, data: { data: window.JSON.stringify(data) } }).then(({ settings }) => {
76
+        this.settings = settings
77
+      })
78
+    },
79
+    getPrizeList() {
80
+      const api = getApi('prize.list')
81
+      request(api).then(({ prizes }) => {
82
+        this.prizes = prizes
83
+      })
84
+    },
85
+    getWinnerList() {
86
+      const api = getApi('winner.list')
87
+      request({ ...api }).then(({ winners }) => {
88
+        this.winners = winners
89
+      })
90
+    },
91
+    searchWinner(params) {
92
+      const api = getApi('winner.list')
93
+      request({ ...api, params }).then(({ winners }) => {
94
+        this.winners = winners
95
+      })
96
+    },
97
+    cancelWinner({ UserId, PrizeId: pid }) {
98
+      const api = getApi('winner.cancel', { UserId })
99
+      request({ ...api, params: { pid }}).then(() => {
100
+        this.winners = this.winners.filter(x => x.Status != -1)
101
+
102
+        this.$message({
103
+            type: 'success',
104
+            message: '取消成功!'
105
+          })
106
+      })
107
+    },
108
+    savePrize(data) {
109
+      const api = getApi('prize.save')
110
+      request({ ...api, data: { data: window.JSON.stringify(data) } }).then(({ prizes }) => {
111
+        this.prizes = prizes
112
+      })
113
+    },
114
+    exportExcel(params) {
115
+      const api = getApi('excel.winner')
116
+      const searchStr = !params ? '' : ['?'].concat(Object.keys(params).map((k) => `${k}=${params[k]}`)).join('&')
117
+      window.open(`http://localhost:8080${api.url}${searchStr}`)
118
+    }
119
+  }
120
+}
121
+</script>
122
+
123
+
124
+<style>
125
+
126
+.el-header, .el-footer {
127
+  color: #fff;
128
+  background-color: rgb(84, 92, 100);
129
+  border-bottom: 1px solid #ebebeb;
130
+}
131
+
132
+.el-header .logo {
133
+  line-height: 60px;
134
+}
135
+
136
+</style>
137
+

+ 3
- 0
src/pages/draw.vue Wyświetl plik

@@ -0,0 +1,3 @@
1
+<template>
2
+  <div></div>
3
+</template>

+ 18
- 0
src/router.js Wyświetl plik

@@ -0,0 +1,18 @@
1
+import VueRouter from 'vue-router'
2
+
3
+const router = new VueRouter({
4
+  routes: [
5
+    {
6
+      path: '/',
7
+      name: 'index',
8
+      component: () => import('./pages/draw.vue')
9
+    },
10
+    {
11
+      path: '/admin',
12
+      name: 'user',
13
+      component: () => import('./pages/admin.vue')
14
+    },
15
+  ],
16
+})
17
+
18
+export default router

+ 62
- 0
src/utils/index.js Wyświetl plik

@@ -0,0 +1,62 @@
1
+
2
+
3
+export function hasKey (o, k) {
4
+  return Object.prototype.hasOwnProperty.call(o, k)
5
+}
6
+
7
+export function objectGet(o = {}, k = '') {
8
+  let found = true
9
+  return k.split('.').reduce((acc, key) => {
10
+    if (!found) return acc;
11
+
12
+    if (acc === 0) {
13
+      if (hasKey(o, key)) {
14
+        return o[key]
15
+      } else {
16
+        found = false
17
+        return {}
18
+      }
19
+    } else {
20
+      if (hasKey(acc, key)) {
21
+        return acc[key]
22
+      } else {
23
+        found = false
24
+        return acc
25
+      }
26
+    }
27
+  }, 0)
28
+}
29
+
30
+export function replaceUrlParams(url, params) {
31
+  if (!params) return url
32
+
33
+  const pathItems = (url || '').split('/')
34
+
35
+  Object.keys(params).forEach((k) => {
36
+    const inx = pathItems.indexOf(`:${k}`)
37
+    if (inx > -1) {
38
+      pathItems[inx] = params[k]
39
+    }
40
+  })
41
+
42
+  return pathItems.join('/')
43
+}
44
+
45
+// groupBy 只支持数组
46
+// it 只支持字符串与函数, 其中字符串必须是对象的一个属性名称
47
+export function groupBy(collection, it) {
48
+  if (Array.isArray(collection)) {
49
+    return collection.reduce((acc, x) => {
50
+      const v = typeof it === 'function' ? it(x) : x[it]
51
+
52
+      if (hasKey(acc, v)) {
53
+        acc[v].push(x)
54
+      } else {
55
+        acc[v] = [x]
56
+      }
57
+      return acc
58
+    }, {})
59
+  } else {
60
+    return {}
61
+  }
62
+}

+ 73
- 0
src/utils/request.js Wyświetl plik

@@ -0,0 +1,73 @@
1
+import axios from 'axios'
2
+import { replaceUrlParams } from './index'
3
+
4
+const MultiForm = 'multipart/form-data'
5
+
6
+export default function request (config = {}, axiosResult = false) {
7
+  let {
8
+    urlParams = undefined,
9
+    contentType = undefined,
10
+    method = 'get',
11
+    url = '',
12
+    data = undefined,
13
+    headers = {},
14
+    ...axiosConf
15
+  } = config
16
+
17
+  url = replaceUrlParams(url, urlParams)
18
+
19
+  if (method === 'get' || method === 'GET') {
20
+    // get 请求丢掉 body 参数
21
+    data = undefined
22
+  } else {
23
+    if (!contentType) {
24
+      contentType = MultiForm
25
+      headers = { ...headers, 'Content-Type': MultiForm }
26
+    }
27
+  }
28
+
29
+  // data 转换为 formdata, 但是只支持一层结构的 plainobject
30
+  if (data && contentType === MultiForm) {
31
+    if (!(data instanceof window.FormData)) {
32
+      data = Object.keys(data).reduce((fmt, k) => {
33
+        if (Array.isArray(data[k])) {
34
+          data[k].forEach(x =>  fmt.append(k, x))
35
+        } else {
36
+          fmt.append(k, data[k])
37
+        }
38
+
39
+        return fmt
40
+      }, new window.FormData)
41
+    }
42
+  }
43
+
44
+  const rtn = axios({
45
+    url,
46
+    method,
47
+    data,
48
+    headers,
49
+    ...axiosConf
50
+  })
51
+
52
+  // 如果不需要业务封装, 返回 axios 原始结果
53
+  if (axiosResult) return rtn
54
+
55
+  // 否则
56
+  return new Promise((resolve, reject) => {
57
+    rtn.then(({ data }) => {
58
+      const { code, message } = data
59
+      
60
+      if (code === 200) {
61
+        resolve(message)
62
+      } else {
63
+        reject(message)
64
+      }
65
+    }).catch((error) => {
66
+      if (error.message) {
67
+        reject(error.message)
68
+      } else {
69
+        reject(`${error.response.status} - ${error.response.statusText}`)
70
+      }
71
+    })
72
+  })
73
+}

+ 12
- 0
vue.config.js Wyświetl plik

@@ -0,0 +1,12 @@
1
+module.exports = {
2
+  baseUrl: '',
3
+  devServer: {
4
+    port: 9000,
5
+    proxy: {
6
+      '/api': {
7
+        target: 'http://localhost:8080',
8
+        changeOrigin: true
9
+      },
10
+    }
11
+  }
12
+}