Files
ci/web/src/views/ProjectCreate.vue
2026-06-18 21:19:47 +08:00

220 lines
7.5 KiB
Vue

<script setup>
import { ref } from 'vue'
import { useRouter } from 'vue-router'
import { createProject } from '../api'
import { ElMessage } from 'element-plus'
const router = useRouter()
const form = ref({
name: '',
description: '',
mode: 'git',
git_url: '',
git_branch: 'master',
git_username: '',
git_password: '',
build_script: '',
run_command: '',
output_binary: '',
env_vars: '',
port: null,
})
const submitting = ref(false)
const handleSubmit = async () => {
if (!form.value.name) {
ElMessage.warning('Project name is required')
return
}
submitting.value = true
try {
await createProject(form.value)
ElMessage.success('Project created')
router.push('/')
} catch (e) {
ElMessage.error(e.response?.data?.error || 'Failed to create project')
} finally {
submitting.value = false
}
}
</script>
<template>
<div class="create-page">
<el-page-header @back="router.push('/')" class="page-back">
<template #content>
<span class="back-title">New Project</span>
</template>
</el-page-header>
<el-card class="form-card" shadow="never">
<el-form :model="form" label-position="top" class="project-form">
<!-- Basic info -->
<div class="form-section">
<h3 class="section-title">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
Basic Information
</h3>
<div class="form-row two-col">
<el-form-item label="Project Name" required>
<el-input v-model="form.name" placeholder="my-project" size="large" />
</el-form-item>
<el-form-item label="Port">
<el-input-number v-model="form.port" :min="1" :max="65535" placeholder="8080" size="large" style="width:100%" />
</el-form-item>
</div>
<el-form-item label="Description">
<el-input v-model="form.description" type="textarea" :rows="2" placeholder="A short description of this project..." />
</el-form-item>
</div>
<!-- Source -->
<div class="form-section">
<h3 class="section-title">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>
Source Code
</h3>
<el-form-item label="Source Mode">
<el-radio-group v-model="form.mode" class="mode-switch">
<el-radio-button value="git">
<span class="radio-inner">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="18" r="3"/><circle cx="6" cy="6" r="3"/><circle cx="18" cy="6" r="3"/><path d="M18 9v1a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2V9"/><path d="M12 12v3"/></svg>
Git Repository
</span>
</el-radio-button>
<el-radio-button value="upload">
<span class="radio-inner">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
File Upload
</span>
</el-radio-button>
</el-radio-group>
</el-form-item>
<template v-if="form.mode === 'git'">
<el-form-item label="Git URL">
<el-input v-model="form.git_url" placeholder="https://gitee.com/user/repo.git" size="large" />
</el-form-item>
<div class="form-row two-col">
<el-form-item label="Branch">
<el-input v-model="form.git_branch" placeholder="master" />
</el-form-item>
<el-form-item label="Username (private repos)">
<el-input v-model="form.git_username" placeholder="optional" />
</el-form-item>
</div>
<el-form-item label="Password / Token">
<el-input v-model="form.git_password" type="password" placeholder="optional" show-password />
</el-form-item>
</template>
<template v-if="form.mode === 'upload'">
<el-alert type="info" :closable="false" show-icon>
After creating this project, go to its detail page to upload your source files as .zip or .tar.gz.
</el-alert>
</template>
</div>
<!-- Build & Run -->
<div class="form-section">
<h3 class="section-title">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="14.5 17.5 3 6 3 3 6 3 17.5 14.5"/><line x1="13" y1="19" x2="19" y2="13"/><line x1="16" y1="16" x2="20" y2="20"/><line x1="19" y1="21" x2="21" y2="19"/></svg>
Build &amp; Run Configuration
</h3>
<el-form-item label="Build Script">
<el-input v-model="form.build_script" type="textarea" :rows="3"
placeholder="go build -o app ." />
</el-form-item>
<div class="form-row two-col">
<el-form-item label="Output Binary">
<el-input v-model="form.output_binary" placeholder="app" />
</el-form-item>
<el-form-item label="Run Command">
<el-input v-model="form.run_command" placeholder="./app" />
</el-form-item>
</div>
<el-form-item label="Environment Variables">
<el-input v-model="form.env_vars" type="textarea" :rows="2"
placeholder='{"DB_HOST": "192.168.1.100", "DB_PORT": "3306"}' />
</el-form-item>
</div>
<div class="form-actions">
<el-button size="large" @click="router.push('/')">Cancel</el-button>
<el-button type="primary" size="large" :loading="submitting" @click="handleSubmit">
Create Project
</el-button>
</div>
</el-form>
</el-card>
</div>
</template>
<style scoped>
.create-page { max-width: 760px; margin: 0 auto; }
.page-back { margin-bottom: 20px; }
.back-title { font-size: 20px; font-weight: 700; color: #1a1d2e; }
.form-card {
border-radius: 14px;
border: 1px solid #ebeef2;
box-shadow: 0 1px 3px #00000005;
}
.form-card :deep(.el-card__body) { padding: 28px 32px; }
/* ── Sections ── */
.form-section {
margin-bottom: 28px;
padding-bottom: 24px;
border-bottom: 1px solid #f0f0f0;
}
.form-section:last-of-type { border-bottom: none; margin-bottom: 24px; padding-bottom: 0; }
.section-title {
display: flex;
align-items: center;
gap: 8px;
font-size: 15px;
font-weight: 700;
color: #1a1d2e;
margin-bottom: 16px;
}
.section-title svg { width: 18px; height: 18px; color: #409eff; }
.form-row { display: flex; gap: 16px; }
.form-row.two-col > * { flex: 1; }
/* ── Mode switch ── */
.mode-switch { width: 100%; }
.mode-switch :deep(.el-radio-button) { flex: 1; }
.mode-switch :deep(.el-radio-button__inner) {
width: 100%;
padding: 14px 20px;
font-weight: 500;
}
.radio-inner {
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
}
.radio-inner svg { width: 16px; height: 16px; }
/* ── Form items ── */
.project-form :deep(.el-form-item__label) {
font-weight: 600;
color: #444;
padding-bottom: 4px;
}
.form-actions {
display: flex;
justify-content: flex-end;
gap: 12px;
padding-top: 8px;
}
</style>