feat: 改版阶段 2:挑战和自由创作共用工作台,学生自己选版本提交
- 新的 Workbench:左边题目(可收起)+ AI 对话,右边预览 / 代码(可编辑),底部版本条; 挑战页和自由创作页都用它,原来的“手动提交”“历史对话”标签换成“粘贴外部代码”和“全部历史” - 不再每轮 AI 回复自动提交:学生点“交这一版”,可交多次,成绩仍取最高分;已交的版本不能重复点 - 手改代码、粘贴外部 AI 代码都存成版本(POST /prompt/versions,source 为 edit / manual), 在版本条和提示词链里标“手改”“外部 AI”;它们进入 AI 上下文,AI 在手改后的代码上继续改; 以前手动提交的回复正文为空时用代码补上;edit 的占位提问不参与提示词层级分类 - 互评从全屏弹窗改成对话里的卡片,打分前不显示作者,每个分数写明含义 - 编辑器代码按任务各存一份(useTaskCode),挑战页“清空”不再清掉教程的代码; 提交列表“复制到编辑器”对挑战写入该任务自己的代码 - 抽出 utils/code.ts(整理代码、拆分整页 HTML);删除 RandomRatingModal、ExternalAIPanel Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ff1eb2982e
commit
9c6c01eba1
29 files changed
+1748
-1069
No files matched your search
@@ -0,0 +1,79 @@
|
||||
<template>
|
||||
<n-modal
|
||||
v-model:show="show"
|
||||
preset="card"
|
||||
title="粘贴外部 AI 生成的代码"
|
||||
style="width: 640px; max-width: 94vw"
|
||||
>
|
||||
<n-form-item label="你在外部 AI 里用的提示词" :show-feedback="false">
|
||||
<n-input
|
||||
v-model:value="prompt"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 6 }"
|
||||
placeholder="把你发给豆包、DeepSeek 等 AI 的话粘贴到这里"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-form-item label="完整的网页代码" :show-feedback="false" style="margin-top: 12px">
|
||||
<n-input
|
||||
v-model:value="raw"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 8, maxRows: 16 }"
|
||||
placeholder="粘贴整页 HTML,里面的 <style> 和 <script> 会自动拆到 CSS 和 JS"
|
||||
class="code-input"
|
||||
/>
|
||||
</n-form-item>
|
||||
<n-text depth="3" class="hint">
|
||||
保存后会成为一个新版本,提示词会记进你的提示词记录里。
|
||||
</n-text>
|
||||
<template #footer>
|
||||
<n-flex justify="end">
|
||||
<n-button @click="show = false">取消</n-button>
|
||||
<n-button
|
||||
type="primary"
|
||||
:disabled="!prompt.trim() || !raw.trim()"
|
||||
:loading="saving"
|
||||
@click="save"
|
||||
>
|
||||
存为新版本
|
||||
</n-button>
|
||||
</n-flex>
|
||||
</template>
|
||||
</n-modal>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref } from "vue"
|
||||
import { splitHtml, type Code } from "../../utils/code"
|
||||
|
||||
const show = defineModel<boolean>("show", { required: true })
|
||||
const props = defineProps<{
|
||||
onSave: (prompt: string, code: Code) => Promise<void>
|
||||
}>()
|
||||
|
||||
const prompt = ref("")
|
||||
const raw = ref("")
|
||||
const saving = ref(false)
|
||||
|
||||
async function save() {
|
||||
saving.value = true
|
||||
try {
|
||||
await props.onSave(prompt.value.trim(), splitHtml(raw.value))
|
||||
prompt.value = ""
|
||||
raw.value = ""
|
||||
show.value = false
|
||||
} finally {
|
||||
saving.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.code-input :deep(textarea) {
|
||||
font-family: var(--wp-font-mono);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.hint {
|
||||
display: block;
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user