You've already forked agentic-coding-workflow
启动项目逻辑
This commit is contained in:
@@ -0,0 +1,206 @@
|
||||
<template>
|
||||
<NModal
|
||||
:show="true"
|
||||
preset="card"
|
||||
:title="profile ? '编辑运行档' : '新建运行档'"
|
||||
:style="{ width: '640px' }"
|
||||
@close="emit('close')"
|
||||
>
|
||||
<NForm label-placement="top">
|
||||
<div class="grid grid-cols-2 gap-3">
|
||||
<NFormItem
|
||||
label="Slug"
|
||||
required
|
||||
>
|
||||
<NInput
|
||||
v-model:value="form.slug"
|
||||
placeholder="dev"
|
||||
:disabled="!!profile"
|
||||
/>
|
||||
</NFormItem>
|
||||
<NFormItem
|
||||
label="名称"
|
||||
required
|
||||
>
|
||||
<NInput
|
||||
v-model:value="form.name"
|
||||
placeholder="Dev server"
|
||||
/>
|
||||
</NFormItem>
|
||||
</div>
|
||||
|
||||
<NFormItem label="描述">
|
||||
<NInput
|
||||
v-model:value="form.description"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 1, maxRows: 3 }"
|
||||
/>
|
||||
</NFormItem>
|
||||
|
||||
<NFormItem
|
||||
label="启动命令"
|
||||
required
|
||||
>
|
||||
<NInput
|
||||
v-model:value="form.command"
|
||||
placeholder="pnpm"
|
||||
/>
|
||||
</NFormItem>
|
||||
|
||||
<NFormItem label="参数(每行一个)">
|
||||
<NInput
|
||||
v-model:value="argsText"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 6 }"
|
||||
placeholder="dev"
|
||||
/>
|
||||
</NFormItem>
|
||||
|
||||
<NFormItem label="环境变量">
|
||||
<div class="w-full">
|
||||
<div
|
||||
v-if="profile && !editEnv"
|
||||
class="text-sm text-gray-500 mb-2"
|
||||
>
|
||||
<span v-if="profile.env_keys.length">已配置:{{ profile.env_keys.join(', ') }}</span>
|
||||
<span v-else>(无)</span>
|
||||
<NButton
|
||||
text
|
||||
type="primary"
|
||||
size="small"
|
||||
class="ml-2"
|
||||
@click="enableEnvEdit"
|
||||
>
|
||||
修改
|
||||
</NButton>
|
||||
</div>
|
||||
<NDynamicInput
|
||||
v-else
|
||||
v-model:value="envPairs"
|
||||
preset="pair"
|
||||
key-placeholder="KEY"
|
||||
value-placeholder="value"
|
||||
/>
|
||||
</div>
|
||||
</NFormItem>
|
||||
|
||||
<NFormItem>
|
||||
<NCheckbox v-model:checked="form.enabled">
|
||||
启用(禁用后不可 start)
|
||||
</NCheckbox>
|
||||
</NFormItem>
|
||||
</NForm>
|
||||
|
||||
<template #footer>
|
||||
<NSpace justify="end">
|
||||
<NButton @click="emit('close')">
|
||||
取消
|
||||
</NButton>
|
||||
<NButton
|
||||
type="primary"
|
||||
:loading="submitting"
|
||||
@click="submit"
|
||||
>
|
||||
保存
|
||||
</NButton>
|
||||
</NSpace>
|
||||
</template>
|
||||
</NModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive } from 'vue'
|
||||
import {
|
||||
NModal,
|
||||
NForm,
|
||||
NFormItem,
|
||||
NInput,
|
||||
NDynamicInput,
|
||||
NCheckbox,
|
||||
NButton,
|
||||
NSpace,
|
||||
useMessage,
|
||||
} from 'naive-ui'
|
||||
import { ApiException } from '@/api/types'
|
||||
import { useRunsStore } from '@/stores/runs'
|
||||
import type { RunProfile, CreateRunProfileBody, UpdateRunProfileBody } from '@/api/runs'
|
||||
|
||||
const props = defineProps<{ wsId: string; profile?: RunProfile | null }>()
|
||||
const emit = defineEmits<{ close: []; saved: [p: RunProfile] }>()
|
||||
const store = useRunsStore()
|
||||
const msg = useMessage()
|
||||
|
||||
const form = reactive({
|
||||
slug: props.profile?.slug ?? '',
|
||||
name: props.profile?.name ?? '',
|
||||
description: props.profile?.description ?? '',
|
||||
command: props.profile?.command ?? '',
|
||||
enabled: props.profile?.enabled ?? true,
|
||||
})
|
||||
const argsText = ref<string>((props.profile?.args ?? []).join('\n'))
|
||||
const envPairs = ref<{ key: string; value: string }[]>([])
|
||||
// 编辑模式下默认不改 env(server 不回传明文值);点"修改"后才整体替换。
|
||||
const editEnv = ref(!props.profile)
|
||||
const submitting = ref(false)
|
||||
|
||||
function enableEnvEdit() {
|
||||
editEnv.value = true
|
||||
envPairs.value = []
|
||||
}
|
||||
|
||||
function parsedArgs(): string[] {
|
||||
return argsText.value
|
||||
.split('\n')
|
||||
.map((s) => s.trim())
|
||||
.filter((s) => s.length > 0)
|
||||
}
|
||||
|
||||
function parsedEnv(): Record<string, string> {
|
||||
const env: Record<string, string> = {}
|
||||
for (const p of envPairs.value) {
|
||||
if (p.key.trim()) env[p.key.trim()] = p.value
|
||||
}
|
||||
return env
|
||||
}
|
||||
|
||||
async function submit() {
|
||||
if (!form.slug.trim() || !form.name.trim() || !form.command.trim()) {
|
||||
msg.warning('slug / 名称 / 启动命令为必填')
|
||||
return
|
||||
}
|
||||
submitting.value = true
|
||||
try {
|
||||
let saved: RunProfile
|
||||
if (props.profile) {
|
||||
const body: UpdateRunProfileBody = {
|
||||
slug: form.slug,
|
||||
name: form.name,
|
||||
description: form.description,
|
||||
command: form.command,
|
||||
args: parsedArgs(),
|
||||
enabled: form.enabled,
|
||||
}
|
||||
// 仅在用户显式修改时才整体替换 env,否则保留原值。
|
||||
if (editEnv.value) body.env = parsedEnv()
|
||||
saved = await store.update(props.profile.id, body)
|
||||
} else {
|
||||
const body: CreateRunProfileBody = {
|
||||
slug: form.slug,
|
||||
name: form.name,
|
||||
description: form.description,
|
||||
command: form.command,
|
||||
args: parsedArgs(),
|
||||
env: parsedEnv(),
|
||||
enabled: form.enabled,
|
||||
}
|
||||
saved = await store.create(props.wsId, body)
|
||||
}
|
||||
emit('saved', saved)
|
||||
emit('close')
|
||||
} catch (e: unknown) {
|
||||
msg.error('保存失败:' + (e instanceof ApiException ? e.body.message : String(e)))
|
||||
} finally {
|
||||
submitting.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user