Skip to content

Commit 0252319

Browse files
committed
feat(#30): collect and show form data
1 parent 16f173d commit 0252319

File tree

11 files changed

+340
-11
lines changed

11 files changed

+340
-11
lines changed

back-end/h5-api/api/work/config/routes.json

+8
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@
6363
"config": {
6464
"policies": []
6565
}
66+
},
67+
{
68+
"method": "GET",
69+
"path": "/works/form/query/:id",
70+
"handler": "Work.queryFormsOfOneWork",
71+
"config": {
72+
"policies": []
73+
}
6674
}
6775
]
6876
}

back-end/h5-api/api/work/controllers/Work.js

+28
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,32 @@ module.exports = {
2121
// eslint-disable-next-line require-atomic-updates
2222
ctx.body = { message: 'success', status: 0 };
2323
},
24+
queryFormsOfOneWork: async (ctx) => {
25+
// move to util module or front-end
26+
function getUuidMap2Name(work) {
27+
const uuidMap2Name = {};
28+
work.pages.forEach(page => {
29+
page.elements.forEach(ele => {
30+
if (ele.name === 'lbp-form-input') {
31+
uuidMap2Name[ele.uuid] = ele.pluginProps.placeholder;
32+
}
33+
});
34+
});
35+
return uuidMap2Name;
36+
}
37+
38+
let work = await strapi.services.work.findOne(ctx.params);
39+
work = work.toJSON();
40+
41+
// learn the query from: https://github.com/strapi/foodadvisor/blob/master/api/api/restaurant/controllers/Restaurant.js#L40
42+
// eslint-disable-next-line no-undef
43+
let formDetails = await Workform.query(qb => {
44+
qb.where('work', '=', work.id);
45+
}).fetchAll();
46+
formDetails = formDetails.toJSON();
47+
48+
const uuidMap2Name = getUuidMap2Name(work);
49+
// eslint-disable-next-line require-atomic-updates
50+
return ctx.body = { uuidMap2Name, formDetails };
51+
},
2452
};

front-end/h5/src/router.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@ export default new Router({
2323
{
2424
path: '/work-manager/form-stat',
2525
name: 'form-stat',
26-
component: () => import('@/views/work-manager/form-stat.vue')
26+
component: () => import('@/views/work-manager/form-stat/index.vue')
27+
},
28+
{
29+
path: '/work-manager/stat-detail/:id',
30+
name: 'stat-detail',
31+
component: () => import('@/views/work-manager/form-stat/detail.vue')
2732
}
2833
]
2934
},

front-end/h5/src/store/modules/editor.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ const state = {
99
work: new Work(),
1010
editingPage: { elements: [] },
1111
editingElement: null,
12-
editingElementEditorConfig: null
12+
editingElementEditorConfig: null,
13+
formDetailOfWork: {
14+
uuidMap2Name: {},
15+
formDetails: []
16+
}
1317
}
1418

1519
// getters

front-end/h5/src/store/modules/work.js

+75-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export const actions = {
3737

3838
new AxiosWrapper({
3939
dispatch,
40+
commit,
4041
loading_name: 'saveWork_loading',
4142
successMsg: '保存作品成功',
4243
customRequest: strapi.updateEntry.bind(strapi)
@@ -52,6 +53,76 @@ export const actions = {
5253
strapi.getEntries('works', {}).then(entries => {
5354
commit('setWorks', entries)
5455
})
56+
},
57+
/**
58+
*
59+
* @param {*} workId
60+
* response demo:
61+
{
62+
"uuidMap2Name": {
63+
"1565596393441": "姓名",
64+
"1565596397671": "学校"
65+
},
66+
"formDetails": [
67+
{
68+
"id": 3,
69+
"form": {
70+
"1565369322603": "abc"
71+
},
72+
"work": 8,
73+
"created_at": "2019-08-09T16:52:28.826Z",
74+
"updated_at": "2019-08-09T16:52:28.832Z"
75+
},
76+
{
77+
"id": 4,
78+
"form": {
79+
"1565595388440": "ddd"
80+
},
81+
"work": 8,
82+
"created_at": "2019-08-11T07:36:54.521Z",
83+
"updated_at": "2019-08-11T07:36:54.526Z"
84+
},
85+
{
86+
"id": 5,
87+
"form": {
88+
"1565595388440": "acd"
89+
},
90+
"work": 8,
91+
"created_at": "2019-08-11T07:45:22.000Z",
92+
"updated_at": "2019-08-11T07:45:22.005Z"
93+
},
94+
{
95+
"id": 6,
96+
"form": {
97+
"1565596393441": "b",
98+
"1565596397671": "a"
99+
},
100+
"work": 8,
101+
"created_at": "2019-08-11T07:59:00.938Z",
102+
"updated_at": "2019-08-11T07:59:00.943Z"
103+
},
104+
{
105+
"id": 7,
106+
"form": {
107+
"1565596393441": "b",
108+
"1565596397671": "a"
109+
},
110+
"work": 8,
111+
"created_at": "2019-08-11T07:59:37.065Z",
112+
"updated_at": "2019-08-11T07:59:37.070Z"
113+
}
114+
]
115+
}
116+
*/
117+
fetchFormsOfWork ({ commit, state, dispatch }, workId) {
118+
// TODO 考虑 return Promise
119+
new AxiosWrapper({
120+
dispatch,
121+
commit,
122+
name: 'editor/formDetailOfWork',
123+
loading_name: 'queryFormsOfWork_loading',
124+
successMsg: '表单查询完毕'
125+
}).get(`/works/form/query/${workId}`)
55126
}
56127
}
57128

@@ -72,5 +143,8 @@ export const mutations = {
72143
// state.work = new Work()
73144
// },
74145
previewWork (state, { type, value }) {},
75-
deployWork (state, { type, value }) {}
146+
deployWork (state, { type, value }) {},
147+
formDetailOfWork (state, { type, value }) {
148+
state.formDetailOfWork = value
149+
}
76150
}

front-end/h5/src/utils/http.js

+8-6
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,14 @@ export const baseClient = axios.create({
1717

1818
export class AxiosWrapper {
1919
// eslint-disable-next-line camelcase
20-
constructor ({ name = 'default', loading_name, responseType = 'json', headers, dispatch, router, successMsg, failMsg, successCallback, failCallback, customRequest }) {
20+
constructor ({ name = 'default', loading_name, responseType = 'json', headers, dispatch, commit, router, successMsg, failMsg, successCallback, failCallback, customRequest }) {
2121
this.name = name
2222
// eslint-disable-next-line camelcase
2323
this.loading_name = loading_name
2424
// eslint-disable-next-line camelcase
2525
this.responseType = responseType
2626
this.dispatch = dispatch
27+
this.commit = commit
2728
this.router = router
2829
this.successMsg = successMsg
2930
this.failMsg = failMsg
@@ -80,7 +81,7 @@ export class AxiosWrapper {
8081
return this.customRequest(...args)
8182
.then(data => {
8283
const handler = this.getCommonResponseHandler({ failMsg: 'Save Failed.' })
83-
handler.call(this, { data: { status: 200, data } })
84+
handler.call(this, { status: 200, data: { data } })
8485
})
8586
.finally(() => this.setLoadingValue(false))
8687
}
@@ -112,7 +113,8 @@ export class AxiosWrapper {
112113
}
113114

114115
setLoadingValue (payload) {
115-
this.dispatch('loading/update', { type: this.loading_name, payload }, { root: true })
116+
// this.dispatch('loading/update', { type: this.loading_name, payload }, { root: true })
117+
this.commit('loading/update', { type: this.loading_name, payload }, { root: true })
116118
}
117119

118120
setDefaultLoadingName (...args) {
@@ -134,16 +136,16 @@ export class AxiosWrapper {
134136
return (response) => {
135137
if (!response.data) {
136138
myMessage.warn(this.failMsg || failMsg)
137-
} else if (response.data.status === 200) {
139+
} else if (response.status === 200) {
138140
this.successMsg && myMessage.success(this.successMsg)
139141
if (this.successCallback) {
140142
this.successCallback(response)
141143
} else {
142-
// this.dispatch({ type: this.name, payload: response.data.data })
144+
this.commit({ type: this.name, value: response.data }, { root: true })
143145
}
144146
} else if (this.responseType === 'json') {
145147
myMessage.error(response.data.msg)
146-
if (response.data.status === 401) {
148+
if (response.status === 401) {
147149
if (this.router) {
148150
this.router.push('/login')
149151
}

front-end/h5/src/views/work-manager/form-stat.vue

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
export const columns = [
2+
{
3+
title: '标题',
4+
dataIndex: 'title',
5+
key: 'title'
6+
},
7+
{
8+
title: 'PV',
9+
dataIndex: 'pv',
10+
key: 'pv'
11+
},
12+
{
13+
title: 'Uv',
14+
dataIndex: 'uv',
15+
key: 'uv'
16+
},
17+
{
18+
title: '表单数',
19+
key: 'formCount',
20+
dataIndex: 'formCount'
21+
},
22+
{
23+
title: 'Action',
24+
key: 'action',
25+
scopedSlots: { customRender: 'action' }
26+
}
27+
]
28+
29+
export const data = [
30+
{
31+
key: '1',
32+
title: 'John Brown',
33+
pv: 32,
34+
uv: 32,
35+
formCount: 2
36+
},
37+
{
38+
key: '2',
39+
title: 'John Brown2',
40+
pv: 32,
41+
uv: 32,
42+
formCount: 2
43+
},
44+
{
45+
key: '3',
46+
title: 'John Brown3',
47+
pv: 32,
48+
uv: 32,
49+
formCount: 2
50+
}
51+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<script>
2+
/**
3+
* [基础数据](/work-manager/form-stat) 对应的页面
4+
*
5+
*/
6+
import { mapState, mapActions } from 'vuex'
7+
8+
export default {
9+
components: {
10+
},
11+
data: () => ({
12+
activeWork: null,
13+
previewVisible: false
14+
}),
15+
computed: {
16+
...mapState('editor', ['works', 'formDetailOfWork']),
17+
computedWorks () {
18+
return this.works.map(w => ({
19+
id: w.id,
20+
title: w.title,
21+
pv: w.pv || 0,
22+
uv: w.uv || 0,
23+
formCount: w.formCount || 0
24+
}))
25+
},
26+
/**
27+
* columns demo: [{"1565369322603":"abc"},{"1565595388440":"ddd"},{"1565595388440":"acd"},{"1565596393441":"b","1565596397671":"a"},{"1565596393441":"b","1565596397671":"a"}]
28+
*/
29+
columns () {
30+
const { uuidMap2Name } = this.formDetailOfWork
31+
// the uuid for input plugin
32+
return Object.entries(uuidMap2Name).map(([uuid, inputName]) => ({
33+
title: inputName,
34+
key: `uuid-${uuid}`,
35+
dataIndex: `uuid-${uuid}`
36+
}))
37+
},
38+
/**
39+
* rows demo: [{"title":"姓名","key":"1565596393441"},{"title":"学校","key":"1565596397671"}]
40+
*
41+
* formDetails example: <[{
42+
"id": 4,
43+
"form": {
44+
"1565595388440": "ddd",
45+
1234: 'abc'
46+
},
47+
"work": 8,
48+
"created_at": "2019-08-11T07:36:54.521Z",
49+
"updated_at": "2019-08-11T07:36:54.526Z"
50+
}]>
51+
*/
52+
rows () {
53+
const { formDetails, uuidMap2Name } = this.formDetailOfWork
54+
const rows = formDetails.map(({ form, id }) => {
55+
const row = {}
56+
Object.entries(form).forEach(([uuid, inputValue = '-']) => {
57+
if (uuidMap2Name[uuid]) {
58+
row[`uuid-${uuid}`] = inputValue
59+
row.id = id
60+
}
61+
})
62+
return row
63+
})
64+
return rows.filter(row => Object.keys(row).length)
65+
}
66+
},
67+
methods: {
68+
...mapActions('editor', [
69+
'fetchWorks',
70+
'fetchFormsOfWork'
71+
]),
72+
deleteWork (item) {
73+
// TODO delete work from work list
74+
},
75+
createWork () {
76+
this.$router.push({ name: 'editor' })
77+
}
78+
},
79+
render (h) {
80+
return (
81+
<div class="works-wrapper">
82+
<a-table columns={this.columns} dataSource={this.rows} row-key="id" scopedSlots={{
83+
action: function (props) {
84+
return [<router-link to={{ name: 'stat-detail', params: { id: props.id } }} >查看数据</router-link>]
85+
}
86+
}}>
87+
</a-table>
88+
</div>
89+
)
90+
},
91+
created () {
92+
// this.fetchWorks()
93+
const workId = this.$route.params.id
94+
this.fetchFormsOfWork(workId)
95+
}
96+
}
97+
</script>

0 commit comments

Comments
 (0)