feat: 完善 Prompt 管理与生成流程配置

This commit is contained in:
王鹏
2026-07-15 17:31:13 +08:00
parent 84d3c8fc05
commit de98ea59b1
93 changed files with 3474 additions and 980 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,291 @@
<template>
<section class="portal-login">
<div class="login-visual" aria-hidden="true">
<div class="login-brand">
<span class="login-logo"></span>
<strong>演示商品</strong>
</div>
<h1>欢迎使用</h1>
<p>登录后继续访问项目功能与个人服务</p>
</div>
<div class="login-panel">
<div class="login-heading">
<span>欢迎回来</span>
<h2>账号登录</h2>
</div>
<el-alert
v-if="roleOptions.length === 0"
title="当前没有可登录的前台角色,请联系管理员检查系统角色配置。"
type="warning"
:closable="false"
class="login-alert"
/>
<el-form :model="form" label-position="top" class="login-form" @submit.native.prevent>
<el-form-item label="账号">
<el-input v-model="form.account" placeholder="请输入账号" prefix-icon="el-icon-user" />
</el-form-item>
<el-form-item label="密码">
<el-input v-model="form.password" type="password" placeholder="请输入密码" prefix-icon="el-icon-lock" show-password />
</el-form-item>
<el-button type="primary" class="login-button" :loading="loading" :disabled="roleOptions.length === 0" @click="handleLogin">登录</el-button>
</el-form>
</div>
</section>
</template>
<script>
const roleOptions = [
]
const defaultRole = roleOptions.length > 0 ? roleOptions[0] : null
export default {
name: "PortalLogin",
data() {
return {
loading: false,
roleOptions,
form: {
roleCode: defaultRole ? defaultRole.value : "",
account: defaultRole ? defaultRole.sampleAccount : "",
password: "123456"
}
}
},
watch: {
"form.roleCode"(roleCode) {
const role = this.roleOptions.find(item => item.value === roleCode)
if (role && (!this.form.account || this.roleOptions.some(item => item.sampleAccount === this.form.account))) {
this.form.account = role.sampleAccount
}
}
},
methods: {
handleLogin() {
if (!this.form.roleCode) {
this.$message.warning("请选择登录角色")
return
}
if (!this.form.account || !this.form.password) {
this.$message.warning("请输入账号和密码")
return
}
this.loading = true
this.request.post("/auth/login", this.form)
.then(res => {
if (!res || res.code !== "200" || !res.data || !res.data.token) {
throw new Error((res && res.msg) || "登录失败")
}
localStorage.setItem("portal-token", res.data.token)
localStorage.setItem("portal-user", JSON.stringify(res.data.user || {
account: this.form.account,
displayName: this.form.account,
roleCode: this.form.roleCode
}))
window.dispatchEvent(new Event("portal-user-change"))
this.$message.success("登录成功")
const redirect = this.$route.query.redirect || "/demo/product"
this.$router.push(redirect)
})
.catch(error => {
this.$message.error(error.message || "登录失败")
})
.finally(() => {
this.loading = false
})
}
}
}
</script>
<style scoped>
.portal-login {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(430px, 36vw);
min-height: 100vh;
background:
linear-gradient(132deg, rgba(20, 124, 131, 0.97), rgba(47, 114, 214, 0.91)),
var(--portal-primary, #167d83);
}
.login-visual {
position: relative;
display: flex;
min-width: 0;
flex-direction: column;
justify-content: center;
overflow: hidden;
padding: 72px clamp(48px, 8vw, 128px);
color: #ffffff;
}
.login-visual::before {
position: absolute;
inset: 0;
display: block;
content: "";
opacity: 0.58;
background:
linear-gradient(42deg, transparent 0 18%, rgba(255, 255, 255, 0.18) 18% 27%, transparent 27% 100%),
linear-gradient(132deg, transparent 0 48%, rgba(246, 186, 51, 0.32) 48% 55%, transparent 55% 100%);
}
.login-brand,
.login-visual h1,
.login-visual p {
position: relative;
z-index: 1;
}
.login-brand {
display: inline-flex;
align-items: center;
gap: 12px;
margin-bottom: 40px;
font-size: 22px;
}
.login-logo {
width: 30px;
height: 30px;
border-radius: 9px 19px 9px 19px;
background: linear-gradient(135deg, #6de5e8 0 38%, #f6c85b 38% 66%, #ffffff 66%);
transform: rotate(45deg);
box-shadow: 0 8px 22px rgba(15, 23, 42, 0.18);
}
.login-visual h1,
.login-visual p {
margin: 0;
}
.login-visual h1 {
max-width: 680px;
font-size: clamp(42px, 5vw, 64px);
font-weight: 700;
letter-spacing: 0;
line-height: 1.18;
}
.login-visual p {
max-width: 520px;
margin-top: 20px;
color: rgba(255, 255, 255, 0.88);
font-size: 17px;
line-height: 1.8;
}
.login-panel {
display: flex;
flex-direction: column;
justify-content: center;
padding: clamp(40px, 5vw, 64px);
background: #ffffff;
box-shadow: -18px 0 48px rgba(15, 23, 42, 0.08);
}
.login-heading span {
color: var(--portal-primary, #167d83);
font-size: 14px;
font-weight: 700;
}
.login-heading h2 {
margin: 8px 0 28px;
color: #111827;
font-size: 30px;
font-weight: 700;
letter-spacing: 0;
}
.login-alert {
margin-bottom: 18px;
}
.login-form {
display: grid;
gap: 2px;
}
.role-select,
.login-button {
width: 100%;
}
.login-form >>> .el-input__inner,
.login-form >>> .el-select .el-input__inner {
height: 44px;
border-color: #dfe5ec;
border-radius: 8px;
}
.login-form >>> .el-input__inner:focus {
border-color: var(--portal-primary, #167d83);
box-shadow: 0 0 0 3px rgba(22, 125, 131, 0.12);
}
.login-button {
height: 44px;
margin-top: 10px;
border-color: var(--portal-primary, #167d83);
border-radius: 8px;
background: var(--portal-primary, #167d83);
font-weight: 600;
box-shadow: 0 10px 22px rgba(22, 125, 131, 0.18);
}
.login-button:hover,
.login-button:focus {
border-color: var(--portal-primary-strong, #11656a);
background: var(--portal-primary-strong, #11656a);
}
@media (max-width: 880px) {
.portal-login {
grid-template-columns: 1fr;
}
.login-visual {
min-height: 220px;
padding: 34px 26px;
}
.login-visual h1 {
font-size: 34px;
}
.login-brand {
margin-bottom: 28px;
}
.login-panel {
padding: 34px 24px 44px;
box-shadow: none;
}
}
@media (max-width: 520px) {
.login-visual {
min-height: 184px;
padding: 26px 22px;
}
.login-brand {
margin-bottom: 20px;
font-size: 18px;
}
.login-visual h1 {
font-size: 30px;
}
.login-visual p {
margin-top: 10px;
font-size: 14px;
}
}
</style>