-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
437 lines (429 loc) · 20 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
<!-- <?!= HtmlService.createHtmlOutputFromFile('css').getContent(); ?> -->
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js"></script>
<script src="https://unpkg.com/[email protected]/dist/dexie.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue-qriously.min.js"></script>
<div id="app">
<v-app>
<v-container>
<v-row justify="center">
<v-col cols="12" md="6">
<v-card>
<v-card-text>
<v-combobox v-model="schoolName" :items="schoolNames" label="学校名"/></v-combobox>
</v-card-text>
<v-card-actions>
<v-btn class="mx-auto" @click="loadSchool">学校情報の読み出し</v-btn>
<v-dialog width="400">
<template v-slot:activator="{on, attr}">
<v-btn v-on="on" v-bind="attr" class="mx-auto" :disabled="schoolName == ''">学校情報のエクスポート</v-btn>
</template>
<v-card>
<qriously :value="`https://zack-msyc86.github.io/manavis/?school=${encodeURI(JSON.stringify(formattedSchoolValue))}`" class="mx-auto":size="400" ></qriously>
</v-card>
</v-dialog>
</v-card-actions>
</v-card>
</v-col>
<v-col cols="12" md="6">
<v-card>
<v-card-text>
<v-text-field v-model="commonTest.expectedPoint" label="共通テスト予想点数" :hint="'ボーダー: '+String(commonTestBorderPoint)" type="number"></v-text-field>
<p>2次試験では合格者平均に達するには{{requiredSecondTestPoint}}点必要になる</p>
<div v-for="s in secondTest.subjects" :key="s.name">
<h3>{{s.name}}</h3>
<v-text-field v-model="s.expectedPoint" label="目標点数" type="number"></v-text-field>
<v-textarea v-model="s.memo" label="メモ" type="number" rows="3"></v-textarea>
</div>
合計{{secondTestExpectedPointSum}}点
</v-card-text>
</v-card>
</v-col>
</v-row>
<v-row>
<!-- 共通テスト -->
<v-col cols="12" md="6">
<v-card>
<v-card-title>共通テスト</v-card-title>
<v-card-text>
<p>合計: {{commonTestPointSum}}点</p>
<v-data-table disable-pagination mobile-breakpoint="0" :items="commonTest.subjects" :headers="subjectsHeaders">
<template v-slot:[`item.menu`]="{ item }">
<v-icon @click="editCommonTestSubject(item)">mdi-pencil</v-icon>
<v-icon @click="deleteCommonTestSubject(item)">mdi-minus</v-icon>
</template>
</v-data-table>
<v-btn rounded class="float-right"><v-icon @click="buildCommonTestSubject">mdi-plus</v-icon></v-btn>
</v-card-text>
<v-card-text>
<v-text-field v-model="commonTest.border" label="ボーダー (%)" type="number"></v-text-field>
</v-card-text>
</v-card>
<v-dialog v-model="commonTest.edit.dialog" width="380">
<v-card>
<v-card-title>編集</v-card-title>
<v-card-text>
<v-text-field v-model="commonTest.edit.item.name" label="科目名"></v-text-field>
<v-text-field v-model="commonTest.edit.item.point" label="得点" type="number"></v-text-field>
<v-btn block color="primary" @click="saveCommonTestSubject">保存</v-btn>
</v-card-text>
</v-card>
</v-dialog>
</v-col>
<!-- 二次試験配点 -->
<v-col cols="12" md="6">
<v-card>
<v-card-title>二次試験</v-card-title>
<v-card-text>
<p>合計: {{secondTestPointSum}}点</p>
<v-data-table disable-pagination mobile-breakpoint="0" :items="secondTest.subjects" :headers="subjectsHeaders">
<template v-slot:[`item.menu`]="{ item }">
<v-icon @click="editSecondTestSubject(item)">mdi-pencil</v-icon>
<v-icon @click="deleteSecondTestSubject(item)">mdi-minus</v-icon>
</template>
</v-data-table>
<v-btn rounded class="float-right"><v-icon @click="buildSecondTestSubject">mdi-plus</v-icon></v-btn>
</v-card-text>
<v-card-subtitle>去年のデータ</v-card-subtitle>
<v-card-text>
<v-text-field v-model="secondTest.previousData.highest" label="合格最高点" type="number"></v-text-field>
<v-text-field v-model="secondTest.previousData.average" label="合格者平均点" type="number"></v-text-field>
<v-text-field v-model="secondTest.previousData.lowest" label="合格最低点" type="number"></v-text-field>
</v-card-text>
</v-card>
<v-dialog v-model="secondTest.edit.dialog" width="380">
<v-card>
<v-card-title>編集</v-card-title>
<v-card-text>
<v-text-field v-model="secondTest.edit.item.name" label="科目名"></v-text-field>
<v-text-field v-model="secondTest.edit.item.point" label="得点" type="number"></v-text-field>
<v-btn block color="primary" @click="saveSecondTestSubject">保存</v-btn>
</v-card-text>
</v-card>
</v-dialog>
</v-col>
</v-row>
<v-row>
<v-col cols="12">
<v-card>
<v-card-title>使い方</v-card-title>
<v-card-subtitle>生徒向け</v-card-subtitle>
<v-card-text>
<p>
大学・学部学科・受験方法等を一番上のカードで入力して、読み出しをする
</p>
<p>
大学データがない場合は
<ul>
<li>共通テストの科目・配点・ボーダー・予想点数を入力する</li>
<li>二次試験の科目・配点と過去の合格者平均等を入力する</li>
</ul>
</p>
<p>
2番目のカードに目標点数とメモを書いて得点戦略を具体化する
</p>
</v-card-text>
<v-card-subtitle>スタッフ向け</v-card-subtitle>
<v-card-text>
スタッフ向けメニューを開く(パスワードが必要)
<p>
大学名・学部学科・受験方法等、科目等が識別できるように学校名を入れる<br/>
例:○○大学○○学部○○学科前期日程数学選択<br/>
配点等のみを保存し、再利用できる。
</p>
<p>
マナビス生番号を入れて保存すると、生徒固有の配点戦略とメモ、学校情報の両方が保存される。
マナビス生番号を入れて読み出すと、生徒固有の配点戦略とメモ、学校情報の両方が読み出される。
</p>
</v-card-text>
<v-card-text>
<p>
学校情報のエクスポートを押すと、QRコードが出てくる。
これを読み込むと、他の端末で同じ学校情報を扱える。
</p>
</v-card-text>
</v-card>
</v-col>
</v-row>
<v-dialog @click:outside="password = ''">
<template v-slot:activator="{on, attr}">
<v-btn v-on="on" v-bind="attr" class="mt-3">スタッフ用ページ</v-btn>
</template>
<v-card>
<v-card-title>スタッフ用メニュー</v-card-title>
<v-card-text v-if="password != 12317">
<v-text-field v-model="password" autofocus></v-text-field>
</v-card-text>
<div v-else>
<v-card-text >
<v-text-field v-model="studentID" label="マナビス生番号"></v-text-field>
<v-combobox v-model="schoolName" :items="schoolNames" label="学校名"/></v-combobox>
</v-card-text>
<v-card-actions>
<v-btn class="mx-auto" @click="saveStudent">保存(個別情報と学校)</v-btn>
<v-btn class="mx-auto" @click="saveSchool">配点等のみ保存(学校ごと)</v-btn>
</v-card-actions>
<v-card-actions>
<v-btn class="mx-auto" @click="loadStudent">生徒情報と学校情報を読み出し</v-btn>
<v-btn class="mx-auto" @click="loadSchool">学校情報の読み出し</v-btn>
</v-card-actions>
<v-card-subtitle>行をクリックして読み出し</v-card-subtitle>
<v-card-text>
<v-data-table disable-pagination mobile-breakpoint="0" :items="schoolNames.map(sn => ({name: sn}))" :headers="schoolTableHeaders" @click:row="loadSchoolByTable">
<template v-slot:[`item.menu`]="{item}">
<v-icon @click.stop="deleteSchool(item.name)">mdi-minus</v-icon>
</template>
</v-data-table>
</v-card-text>
</div>
</v-card>
</v-dialog>
</v-container>
<v-snackbar v-model="snackbar.value">
{{snackbar.text}}
</v-snackbar>
</v-app>
</div>
<script>
const db = new Dexie("manavis").version(1);
db.stores({
students: 'id',
schools: 'name'
})
Vue.use(window['vue-qriously']);
const app = new Vue({
el: '#app',
vuetify: new Vuetify(),
data(){
return {
db: db.db,
password: "",
schoolName: "",
schoolNames: [],
schoolTableHeaders: [{ text: 'Name', value: 'name'}, { text: 'Delete', value: 'menu'}],
studentID: "",
commonTest: {
subjects: [
{ name: '英語R', point: 100 },
{ name: '英語L', point: 100 },
{ name: '国語', point: 200 },
{ name: '数学IA', point: 100 },
{ name: '数学IIB', point: 100 },
{ name: '物理', point: 100 },
{ name: '化学', point: 100 },
{ name: '公民', point: 100 },
],
border: 70,
edit: {
item: {},
dialog: false,
},
expectedPoint: 630,
},
secondTest: {
subjects: [
{ name: '英語', point: 500, expectedPoint: 350, memo: "" },
{ name: '数学', point: 500, expectedPoint: 350, memo: "" },
],
previousData: { lowest: 1130, highest: 1530, average: 1330 },
edit: {
item: {},
dialog: false,
},
},
subjectsHeaders: [
{ text: 'Name', value: 'name'},
{ text: 'Point', value: 'point'},
{ text: 'Menu', value: 'menu'},
],
snackbar: {
value: false,
text: "",
}
}
},
methods: {
buildCommonTestSubject(){
this.commonTest.edit.item = {}
this.commonTest.edit.dialog = true
},
editCommonTestSubject(item){
this.commonTest.edit.item = item
this.commonTest.edit.dialog = true
},
saveCommonTestSubject(){
if(!this.commonTest.subjects.map(s => s.name).includes(this.commonTest.edit.item.name)){
this.commonTest.subjects.push(this.commonTest.edit.item)
}
this.commonTest.edit.dialog = false
},
deleteCommonTestSubject(item){
const index = this.commonTest.subjects.indexOf(item)
this.commonTest.subjects.splice(index, 1)
},
buildSecondTestSubject(){
this.secondTest.edit.item = {}
this.secondTest.edit.dialog = true
},
editSecondTestSubject(item){
this.secondTest.edit.item = item
this.secondTest.edit.dialog = true
},
saveSecondTestSubject(){
if(!this.secondTest.subjects.map(s => s.name).includes(this.secondTest.edit.item.name)){
this.secondTest.subjects.push(this.secondTest.edit.item)
}
this.secondTest.edit.dialog = false
},
deleteSecondTestSubject(item){
const index = this.secondTest.subjects.indexOf(item)
this.secondTest.subjects.splice(index, 1)
},
saveStudent(){
if(this.studentID == "" || this.schoolName == ""){
console.log("student id empty")
alert("生徒番号か学校名が空です")
return
}
this.saveSchool()
this.db.students.put({
id: this.studentID,
schoolName: this.schoolName,
secondTestSubjects: this.secondTest.subjects.map(s => ({ name: s.name, expectedPoint: s.expectedPoint, memo: s.memo })),
commonTestExpectedPoint: this.commonTest.expectedPoint
})
this.db.students.get(this.studentID, student => console.log(student))
this.notice(`${this.studentID}を保存しました`)
},
saveSchool(){
if(this.schoolName == ""){
alert("学校名が空です")
return
}
this.db.schools.put(this.formattedSchoolValue)
this.db.schools.get(this.schoolName, s => console.log(s))
this.updateSchoolNames()
this.notice(`${this.schoolName}を保存しました`)
},
loadSchool(){
if(this.schoolName == ""){
alert("学校名が空です")
return
}
return this.db.schools.get(this.schoolName, school => {
this.commonTest.subjects = school.commonTest.subjects
this.commonTest.border = school.commonTest.border
this.secondTest.subjects = school.secondTest.subjects.map(s => ({...s, expectedPoint: s.point*0.6, memo: ""}))
this.secondTest.previousData = school.secondTest.previousData
})
this.notice(`${this.schoolName}を読み出しました`)
},
loadSchoolByTable(e){
this.schoolName = e.name,
this.loadSchool()
},
deleteSchool(sn){
if(!confirm(`本当に${sn}を削除しますか?`)){return}
this.db.schools.delete(sn)
this.notice("削除しました")
this.updateSchoolNames()
},
loadStudent(){
if(this.studentID == ""){
console.log("student id empty")
alert("生徒番号が空です")
return
}
this.db.students.get(this.studentID, student => {
this.schoolName = student.schoolName
this.loadSchool().then(() => {
this.secondTest.subjects.forEach( s => {
const d = student.secondTestSubjects.find(sts => s.name == sts.name)
s.expectedPoint = d.expectedPoint
s.memo = d.memo
})
this.commonTest.expectedPoint = student.commonTestExpectedPoint
})
})
this.notice(`${this.studentID}を読み出しました`)
},
async importSchoolData(){
const importData = getUrlQueries().school
if(!!importData){
data = JSON.parse(importData)
console.log(this.schoolNames, data.name)
if(!this.schoolNames.includes(data.name) || confirm(`${data.name}を上書きしてもよろしいですか?`)){
await this.db.schools.put(data)
await this.updateSchoolNames()
alert(`${data.name}を読み込みました`)
window.location.href = getPathFromUrl(document.location.href)
}
}
},
updateSchoolNames(){
return this.db.schools.toArray(vals => this.schoolNames = vals.map(v => v.name))
},
notice(message){
this.snackbar.value = true
this.snackbar.text = message
}
},
computed: {
commonTestPointSum(){ return this.commonTest.subjects.reduce((sum, element) => sum + Number(element.point), 0) },
secondTestPointSum(){ return this.secondTest.subjects.reduce((sum, element) => sum + Number(element.point), 0) },
secondTestExpectedPointSum(){ return this.secondTest.subjects.reduce((sum, element) => sum + Number(element.expectedPoint), 0) },
commonTestBorderPoint(){ return this.commonTestPointSum*this.commonTest.border/100 },
requiredSecondTestPoint(){ return this.secondTest.previousData.average - this.commonTest.expectedPoint },
formattedSchoolValue(){
return {
name: this.schoolName,
commonTest: {
subjects: this.commonTest.subjects,
border: this.commonTest.border
},
secondTest: {
subjects: this.secondTest.subjects.map(s => ({ name: s.name, point: s.point})),
previousData: this.secondTest.previousData
}
}
}
},
async mounted(){
console.log("v2")
await this.updateSchoolNames()
this.$nextTick(() => {
this.importSchoolData()
})
}
});
function getUrlQueries() {
var queryStr = window.location.search.slice(1); // 文頭?を除外
queries = {};
// クエリがない場合は空のオブジェクトを返す
if (!queryStr) {
return queries;
}
// クエリ文字列を & で分割して処理
queryStr.split('&').forEach(function(queryStr) {
// = で分割してkey,valueをオブジェクトに格納
var queryArr = queryStr.split('=');
queries[queryArr[0]] = decodeURIComponent(queryArr[1]);
});
return queries;
}
function getPathFromUrl(url) {
return url.split(/[?#]/)[0];
}
</script>
</body>
</html>