Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
lexile_question
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
template admin
lexile_question
Commits
ee8a8474
Commit
ee8a8474
authored
Feb 22, 2025
by
liujiangnan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat
parent
9d944887
Changes
4
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
580 additions
and
93 deletions
+580
-93
index.css
form/index.css
+149
-1
index.html
form/index.html
+101
-4
index.js
form/index.js
+238
-22
package-lock.json
package-lock.json
+92
-66
No files found.
form/index.css
View file @
ee8a8474
.edit-data
{
.edit-data
{
padding
:
10px
;
padding
:
10px
;
}
.el-card
{
display
:
inline-block
;
margin
:
3px
;
}
.data-card
{
position
:
relative
;
width
:
90%
;
vertical-align
:
top
;
}
.data-card
.el-card__body
{
padding
:
15px
20px
0px
;
}
.audio-uploader
{
text-align
:
left
;
margin-bottom
:
10px
;
}
audio
{
margin
:
10px
0
;
}
.el-form-item
{
margin-bottom
:
15px
;
}
.delete-btn-wrapper
{
position
:
absolute
;
bottom
:
10px
;
left
:
0
;
right
:
0
;
text-align
:
center
;
}
/* 音频信息显示样式 */
.audio-info
{
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
margin-top
:
10px
;
padding
:
8px
12px
;
background
:
#f5f7fa
;
border-radius
:
4px
;
}
.audio-file-info
{
flex
:
1
;
overflow
:
hidden
;
margin-right
:
10px
;
}
.audio-file-info
.filename
{
display
:
block
;
font-size
:
14px
;
color
:
#606266
;
overflow
:
hidden
;
text-overflow
:
ellipsis
;
white-space
:
nowrap
;
}
.audio-file-info
.file-meta
{
font-size
:
12px
;
color
:
#909399
;
}
.audio-play-btn
{
font-size
:
30px
;
color
:
#409EFF
;
cursor
:
pointer
;
transition
:
all
0.3s
;
}
.audio-play-btn
:hover
{
color
:
#66b1ff
;
}
/* 图片上传区域样式 */
.image-uploader
{
width
:
120px
;
height
:
120px
;
line-height
:
120px
;
border
:
1px
dashed
#d9d9d9
;
border-radius
:
6px
;
cursor
:
pointer
;
position
:
relative
;
overflow
:
hidden
;
}
.image-uploader
.el-upload
{
width
:
120px
;
height
:
120px
;
}
.image-uploader
:hover
{
border-color
:
#409EFF
;
}
.upload-icon
{
font-size
:
28px
;
color
:
#8c939d
;
width
:
120px
;
height
:
120px
;
line-height
:
120px
;
text-align
:
center
;
}
.image-preview
{
width
:
100%
;
height
:
100%
;
position
:
relative
;
}
.uploaded-image
{
width
:
100%
;
height
:
100%
;
object-fit
:
cover
;
}
.image-actions
{
position
:
absolute
;
top
:
0
;
left
:
0
;
width
:
100%
;
height
:
100%
;
background
:
rgba
(
0
,
0
,
0
,
0.5
);
display
:
flex
;
justify-content
:
center
;
align-items
:
center
;
opacity
:
0
;
transition
:
opacity
0.3s
;
}
.image-preview
:hover
.image-actions
{
opacity
:
1
;
}
.image-actions
i
{
color
:
#fff
;
font-size
:
20px
;
margin
:
0
10px
;
cursor
:
pointer
;
}
.image-actions
i
:hover
{
transform
:
scale
(
1.2
);
}
}
\ No newline at end of file
form/index.html
View file @
ee8a8474
...
@@ -15,10 +15,107 @@
...
@@ -15,10 +15,107 @@
<script
src=
"//teach.cdn.ireadabc.com/h5template/h5-static-lib/js/element-ui/index.js"
></script>
<script
src=
"//teach.cdn.ireadabc.com/h5template/h5-static-lib/js/element-ui/index.js"
></script>
</head>
</head>
<body>
<body>
<div
class=
"edit-data"
>
<div
class=
"edit-data"
>
<!-- 简单的例子,一个输入框+一个按钮,保存输入框的信息 -->
<el-card
class=
"data-card"
v-for=
"item, index in data"
:key=
"index"
>
test:
<input
type=
"text"
name=
"test"
/>
<div
slot=
"header"
class=
"clearfix"
>
<input
id=
"save"
type=
"button"
value=
"保存"
>
<span>
题目{{index + 1}}
</span>
<el-button
style=
"float: right; padding: 3px 0"
type=
"text"
@
click=
"deleteConf(index)"
>
删除
</el-button>
</div>
<div>
<el-form
label-width=
"90px"
>
<el-form-item
label=
"题干图片"
>
<div
class=
"image-uploader"
>
<el-upload
:action=
"uploadUrl"
:data=
"uploadData"
:show-file-list=
"false"
:on-success=
"(res, file) => handleImageSuccess(res, file, index)"
:before-upload=
"beforeImageUpload"
>
<div
v-if=
"data[index].image_url"
class=
"image-preview"
>
<img
:src=
"data[index].image_url"
class=
"uploaded-image"
>
<div
class=
"image-actions"
>
<i
class=
"el-icon-zoom-in"
@
click
.
stop=
"previewImage(data[index].image_url)"
></i>
<i
class=
"el-icon-delete"
@
click
.
stop=
"removeImage(index)"
></i>
</div>
</div>
<i
v-else
class=
"el-icon-plus upload-icon"
></i>
</el-upload>
</div>
</el-form-item>
<el-form-item
label=
"题干"
>
<el-input
type=
"textarea"
v-model=
"data[index].question"
placeholder=
"请输入题干英文"
@
change=
"save"
></el-input>
</el-form-item>
<!-- 新增音频上传和预览部分 -->
<el-form-item
label=
"题干音频"
>
<div
class=
"audio-uploader"
>
<el-upload
:action=
"uploadUrl"
:data=
"uploadData"
:on-success=
"(res, file) => handleAudioSuccess(res, file, index)"
:before-upload=
"beforeAudioUpload"
:show-file-list=
"false"
>
<el-button
size=
"small"
type=
"primary"
>
{{ data[index].audio_url ? '重新上传' : '上传' }}
</el-button>
<span
v-if=
"data[index].audio_url"
class=
"filename"
@
click
.
stop=
"togglePlay(index)"
>
{{ data[index].audio_name }}(点击播放)
</span>
<audio
:ref=
"'audio' + index"
:src=
"data[index].audio_url"
@
ended
.
stop=
"audioEnded(index)"
style=
"display: none;"
></audio>
</el-upload>
</div>
</el-form-item>
<el-form-item
v-for=
"(option, optionIndex) in data[index].options"
:key=
"optionIndex"
:label=
"'选项' + (optionIndex + 1)"
>
<el-row
style=
"border: 1px solid #E4E7ED; padding: 10px;"
>
<el-col
:span=
"6"
>
<div
class=
"image-uploader"
style=
"display: inline-block;"
>
<el-upload
:action=
"uploadUrl"
:data=
"uploadData"
:show-file-list=
"false"
:on-success=
"(res, file) => handleOptionImageSuccess(res, file, index, optionIndex)"
:before-upload=
"beforeImageUpload"
>
<div
v-if=
"data[index].options[optionIndex].image_url"
class=
"image-preview"
>
<img
:src=
"data[index].options[optionIndex].image_url"
class=
"uploaded-image"
>
<div
class=
"image-actions"
>
<i
class=
"el-icon-zoom-in"
@
click
.
stop=
"previewImage(data[index].options[optionIndex].image_url)"
></i>
<i
class=
"el-icon-delete"
@
click
.
stop=
"removeOptionImage(index, optionIndex)"
></i>
</div>
</div>
<i
v-else
class=
"el-icon-plus upload-icon"
></i>
</el-upload>
</div>
</el-col>
<el-col
:span=
"18"
>
<el-input
style=
"width: 60%;"
v-model=
"data[index].options[optionIndex].text"
placeholder=
"请输入选项英文"
@
change=
"save"
>
</el-input><br>
<div
class=
"audio-uploader"
>
<el-upload
:action=
"uploadUrl"
:data=
"uploadData"
:on-success=
"(res, file) => handleOptionAudioSuccess(res, file, index, optionIndex)"
:before-upload=
"beforeAudioUpload"
:show-file-list=
"false"
>
<el-button
size=
"small"
type=
"primary"
>
{{ data[index].options[optionIndex].audio_url ? '重新上传' : '上传' }}音频
</el-button>
<span
v-if=
"data[index].options[optionIndex].audio_url"
class=
"filename"
@
click
.
stop=
"toggleOptionPlay(index, optionIndex)"
>
{{ data[index].options[optionIndex].audio_name }}(点击播放)
</span>
<audio
:ref=
"'audio' + index + '-' + optionIndex"
:src=
"data[index].options[optionIndex].audio_url"
@
ended
.
stop=
"audioOptionEnded(index, optionIndex)"
style=
"display: none;"
></audio>
</el-upload>
</div>
<el-checkbox
v-model=
"data[index].options[optionIndex].is_correct"
@
change=
"save"
>
正确
</el-checkbox>
<el-button
style=
"float: right;"
icon=
"el-icon-delete"
size=
"small"
type=
"primary"
@
click
.
stop=
"deleteOption(index, optionIndex)"
>
删除选项
</el-button>
</el-col>
</el-row>
</el-form-item>
<el-form-item>
<el-button
size=
"small"
type=
"primary"
@
click
.
stop=
"addOption(index)"
>
增加选项
</el-button>
</el-form-item>
</el-form>
</div>
</el-card>
<el-card
shadow=
"hover"
class=
"data-card"
>
<div
style=
"cursor: pointer; display: flex; justify-content: center; align-items: center; height: 80px;"
@
click=
"addConfig"
>
<el-button
class=
"btn"
type=
"text"
size=
"mini"
icon=
"el-icon-plus"
>
新加
</el-button>
</div>
</el-card>
</div>
</div>
</body>
</body>
<script
src=
"./index.js"
></script>
<script
src=
"./index.js"
></script>
...
...
form/index.js
View file @
ee8a8474
...
@@ -10,26 +10,242 @@ var uploadData = window.courseware.uploadData(); //上传文件必须要的参
...
@@ -10,26 +10,242 @@ var uploadData = window.courseware.uploadData(); //上传文件必须要的参
*/
*/
//对应模板的名称,这个可以不写,但是最好是能写上,同时开发多个模板的情况下如果不写这个,本地缓存可能会存在混乱
//对应模板的名称,这个可以不写,但是最好是能写上,同时开发多个模板的情况下如果不写这个,本地缓存可能会存在混乱
var
key
=
"
h5_test
"
;
var
key
=
"
lexile_question
"
;
$
(
function
(){
new
Vue
({
window
.
courseware
.
getData
(
function
(
data
){
el
:
'
.edit-data
'
,
//数据加载完,才算页面加载完成
created
()
{
//获取数据
window
.
courseware
.
getData
((
data
)
=>
{
if
(
data
&&
data
.
test
){
this
.
data
=
data
||
[];
$
(
"
[name='test']
"
).
val
(
data
.
test
);
},
key
);
}
window
[
'
air
'
].
getUploadCallback
=
(
url
,
data
)
=>
{
this
.
uploadUrl
=
url
;
//绑定点击事件
this
.
uploadData
=
data
;
$
(
'
#save
'
).
on
(
'
click
'
,
function
(){
};
var
test
=
$
(
"
[name='test']
"
).
val
();
},
data
()
{
//保存新增或修改的数据
return
{
window
.
courseware
.
setData
({
test
:
test
},
function
(){
data
:
[],
uploadUrl
:
window
.
courseware
.
uploadUrl
(),
uploadData
:
window
.
courseware
.
uploadData
(),
}
},
methods
:
{
handleAudioSuccess
(
res
,
file
,
index
)
{
// 假设上传接口返回的音频URL在 res.url 中
this
.
data
[
index
].
audio_url
=
res
.
url
;
this
.
data
[
index
].
audio_name
=
file
.
name
;
// 计算文件大小
const
size
=
file
.
size
;
if
(
size
<
1024
)
{
this
.
data
[
index
].
audio_size
=
size
+
'
B
'
;
}
else
if
(
size
<
1024
*
1024
)
{
this
.
data
[
index
].
audio_size
=
(
size
/
1024
).
toFixed
(
2
)
+
'
KB
'
;
}
else
{
this
.
data
[
index
].
audio_size
=
(
size
/
(
1024
*
1024
)).
toFixed
(
2
)
+
'
MB
'
;
}
// 获取音频时长
const
audio
=
new
Audio
(
res
.
url
);
audio
.
addEventListener
(
'
loadedmetadata
'
,
()
=>
{
const
duration
=
audio
.
duration
;
const
minutes
=
Math
.
floor
(
duration
/
60
);
const
seconds
=
Math
.
floor
(
duration
%
60
);
this
.
data
[
index
].
audio_duration
=
`
${
minutes
}
:
${
seconds
.
toString
().
padStart
(
2
,
'
0
'
)}
`
;
});
this
.
save
();
},
handleOptionAudioSuccess
(
res
,
file
,
index
,
optionIndex
)
{
// 假设上传接口返回的音频URL在 res.url 中
this
.
data
[
index
].
options
[
optionIndex
].
audio_url
=
res
.
url
;
this
.
data
[
index
].
options
[
optionIndex
].
audio_name
=
file
.
name
;
// 计算文件大小
const
size
=
file
.
size
;
if
(
size
<
1024
)
{
this
.
data
[
index
].
options
[
optionIndex
].
audio_size
=
size
+
'
B
'
;
}
else
if
(
size
<
1024
*
1024
)
{
this
.
data
[
index
].
options
[
optionIndex
].
audio_size
=
(
size
/
1024
).
toFixed
(
2
)
+
'
KB
'
;
}
else
{
this
.
data
[
index
].
options
[
optionIndex
].
audio_size
=
(
size
/
(
1024
*
1024
)).
toFixed
(
2
)
+
'
MB
'
;
}
// 获取音频时长
const
audio
=
new
Audio
(
res
.
url
);
audio
.
addEventListener
(
'
loadedmetadata
'
,
()
=>
{
const
duration
=
audio
.
duration
;
const
minutes
=
Math
.
floor
(
duration
/
60
);
const
seconds
=
Math
.
floor
(
duration
%
60
);
this
.
data
[
index
].
options
[
optionIndex
].
audio_duration
=
`
${
minutes
}
:
${
seconds
.
toString
().
padStart
(
2
,
'
0
'
)}
`
;
});
this
.
save
();
},
// 播放/暂停音频
togglePlay
(
index
)
{
const
audio
=
this
.
$refs
[
'
audio
'
+
index
][
0
];
if
(
this
.
data
[
index
].
isPlaying
)
{
audio
.
pause
();
this
.
data
[
index
].
isPlaying
=
false
;
}
else
{
// 先停止其他正在播放的音频
this
.
data
.
forEach
((
item
,
i
)
=>
{
if
(
i
!==
index
&&
item
.
isPlaying
)
{
this
.
$refs
[
'
audio
'
+
i
][
0
].
pause
();
item
.
isPlaying
=
false
;
}
});
audio
.
play
();
this
.
data
[
index
].
isPlaying
=
true
;
}
},
toggleOptionPlay
(
index
,
optionIndex
)
{
const
audio
=
this
.
$refs
[
'
audio
'
+
index
+
'
-
'
+
optionIndex
][
0
];
if
(
this
.
data
[
index
].
options
[
optionIndex
].
isPlaying
)
{
audio
.
pause
();
this
.
data
[
index
].
options
[
optionIndex
].
isPlaying
=
false
;
}
else
{
// 先停止其他正在播放的音频
this
.
data
[
index
].
options
.
forEach
((
item
,
i
)
=>
{
if
(
i
!==
optionIndex
&&
item
.
isPlaying
)
{
this
.
$refs
[
'
audio
'
+
index
+
'
-
'
+
i
][
0
].
pause
();
item
.
isPlaying
=
false
;
}
});
audio
.
play
();
this
.
data
[
index
].
options
[
optionIndex
].
isPlaying
=
true
;
}
},
// 音频播放结束
audioEnded
(
index
)
{
this
.
data
[
index
].
isPlaying
=
false
;
},
audioOptionEnded
(
index
,
optionIndex
)
{
this
.
data
[
index
].
options
[
optionIndex
].
isPlaying
=
false
;
},
beforeAudioUpload
(
file
)
{
const
isAudio
=
file
.
type
.
startsWith
(
'
audio/
'
);
const
isLt20M
=
file
.
size
/
1024
/
1024
<
20
;
if
(
!
isAudio
)
{
this
.
$message
.
error
(
'
只能上传音频文件!
'
);
return
false
;
}
if
(
!
isLt20M
)
{
this
.
$message
.
error
(
'
音频大小不能超过 20MB!
'
);
return
false
;
}
return
true
;
},
save
()
{
// 保存新增或修改的数据
window
.
courseware
.
setData
(
this
.
data
,
()
=>
{
//保存数据也是异步的
//保存数据也是异步的
alert
(
"
保存成功!
"
);
this
.
$message
.
success
(
"
实时保存成功
"
);
},
key
);
},
key
);
},
})
deleteConf
(
index
)
{
},
key
);
this
.
data
.
splice
(
index
,
1
);
})
this
.
save
();
\ No newline at end of file
},
addConfig
()
{
this
.
data
.
push
({
question
:
''
,
audio_url
:
''
,
image_url
:
''
,
audio_name
:
''
,
audio_size
:
''
,
audio_duration
:
''
,
isPlaying
:
false
,
options
:
[],
});
this
.
save
();
},
addOption
(
index
)
{
this
.
data
[
index
].
options
.
push
({
image_url
:
''
,
audio_url
:
''
,
audio_name
:
''
,
text
:
''
,
is_correct
:
false
,
});
this
.
save
();
},
deleteOption
(
index
,
optionIndex
)
{
this
.
data
[
index
].
options
.
splice
(
optionIndex
,
1
);
this
.
save
();
},
// 图片上传成功的回调
handleImageSuccess
(
res
,
file
,
index
)
{
// 假设上传接口返回的图片URL在 res.url 中
console
.
log
(
res
,
file
,
index
);
this
.
data
[
index
].
image_url
=
res
.
url
;
this
.
save
();
},
handleOptionImageSuccess
(
res
,
file
,
index
,
optionIndex
)
{
this
.
data
[
index
].
options
[
optionIndex
].
image_url
=
res
.
url
;
this
.
save
();
},
// 图片上传前的验证
beforeImageUpload
(
file
)
{
const
isImage
=
file
.
type
.
startsWith
(
'
image/
'
);
const
isLt2M
=
file
.
size
/
1024
/
1024
<
5
;
if
(
!
isImage
)
{
this
.
$message
.
error
(
'
只能上传图片文件!
'
);
return
false
;
}
if
(
!
isLt2M
)
{
this
.
$message
.
error
(
'
图片大小不能超过 2MB!
'
);
return
false
;
}
return
true
;
},
// 预览图片
previewImage
(
url
)
{
// 使用 Element UI 的 Image 组件预览
const
h
=
this
.
$createElement
;
this
.
$msgbox
({
title
:
'
图片预览
'
,
message
:
h
(
'
img
'
,
{
attrs
:
{
src
:
url
,
style
:
'
max-width: 100%; max-height: 500px;
'
}
}),
showCancelButton
:
false
,
confirmButtonText
:
'
关闭
'
});
},
removeImage
(
index
)
{
this
.
$confirm
(
'
确定要删除这张图片吗?
'
,
'
提示
'
,
{
confirmButtonText
:
'
确定
'
,
cancelButtonText
:
'
取消
'
,
type
:
'
warning
'
}).
then
(()
=>
{
this
.
data
[
index
].
image_url
=
''
;
this
.
save
();
this
.
$message
({
type
:
'
success
'
,
message
:
'
删除成功!
'
});
}).
catch
(()
=>
{
});
},
removeOptionImage
(
index
,
optionIndex
)
{
this
.
data
[
index
].
options
[
optionIndex
].
image_url
=
''
;
this
.
save
();
}
},
computed
:
{
}
});
package-lock.json
View file @
ee8a8474
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment