登录修改

This commit is contained in:
jingna 2025-06-04 18:32:43 +08:00
parent 4dc7853a14
commit ac50f51518
26 changed files with 422 additions and 17 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 356 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

View File

@ -233,6 +233,13 @@ export const routes: AppRouteRecordRaw[] = [
hidden: true, hidden: true,
meta: {}, meta: {},
component: () => import('@/viewsnew/application/SfcEditor/index.vue') component: () => import('@/viewsnew/application/SfcEditor/index.vue')
},
{
path: '/SystemLogin',
name: 'SystemLogin',
hidden: true,
meta: {},
component: () => import('@/viewsnew/application/SystemLogin.vue')
} }
] ]

View File

@ -1,13 +1,16 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import Navbar from '@/viewsnew/application/SfcEditor/Navbar.vue' // import Navbar from '@/viewsnew/application/SfcEditor/Navbar.vue'
import Navbar from '@/viewsnew/application/sfcEditor/previewNavSfc.vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { getMenuTree } from '@/api/permission/menu' import { getMenuTree } from '@/api/permission/menu'
import { moduleList } from '@/api/application/module'
const route = useRoute() const route = useRoute()
const applicationId:any = ref('') const applicationId:any = ref('')
const menuList = ref([]) const menuList = ref([])
const isNavbar = ref(false) const isNavbar = ref(false)
const projectName:any = ref('') const projectName:any = ref('')
const projectList:any = ref({})
onMounted(()=>{ onMounted(()=>{
if (route.query.id) { if (route.query.id) {
applicationId.value = route.query.id applicationId.value = route.query.id
@ -23,14 +26,27 @@ function getmenuinfo() {
} }
getMenuTree(params).then(res => { getMenuTree(params).then(res => {
menuList.value = res.data menuList.value = res.data
isNavbar.value = true const paramss = {appId:applicationId.value}
moduleList(paramss).then(ress => {
var arr = ress.data.data
let list:any = {}
arr.forEach((item:any) => {
if(item.type == '02' && item.node_type == '02'){
list = item
}
})
if(list.id){
projectList.value = list
isNavbar.value = true
}
})
}) })
} }
</script> </script>
<template> <template>
<div class="system-box"> <div class="system-box">
<Navbar v-if="isNavbar" :menuList="menuList" :projectName="projectName" <Navbar v-if="isNavbar" :menuList="menuList" :projectName="projectName"
:isFixed="true" :applicationId="applicationId" :isExecuteEvent ="false"> :isFixed="true" :projectId="projectList.id" :applicationId="applicationId" :isExecuteEvent="false">
</Navbar> </Navbar>
</div> </div>
</template> </template>
@ -39,5 +55,6 @@ function getmenuinfo() {
.system-box { .system-box {
width: 100%; width: 100%;
height: 100vh; height: 100vh;
overflow: hidden;
} }
</style> </style>

View File

@ -0,0 +1,189 @@
<script lang="ts" setup>
import { ref, watch, onMounted, onBeforeUnmount, shallowRef } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
import { useRouter } from 'vue-router'
const router = useRouter()
const props = defineProps({
id: String,
name: String
})
const form = ref({
username: '',
password: ''
})
const loginRules = ref({
username: [
{ required: true, message: '请输入用户名', trigger: 'blur' }
],
password: [
{ required: true, message: '请输入密码', trigger: 'blur' }
]
})
const ruleFormRef = ref<FormInstance>()
const loginTitle: any = ref('')
const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return
await formEl.validate((valid, fields) => {
if (valid) {
router.push({
path: '/PreviewSystem',
query: { id: props.id, name: props.name }
})
} else {
}
})
}
onMounted(() => {
loginTitle.value = props.name
})
onBeforeUnmount(() => {
});
</script>
<template>
<div class="login-box">
<div class="login-container">
<div class="login-title">
<div class="login-title-left"><img src="@/assets/img/titleline.png" alt=""></div>
<div class="login-title-text">{{ loginTitle }}</div>
<div class="login-title-right"><img src="@/assets/img/titleline.png" alt=""></div>
</div>
<div class="login-form">
<div class="login-form-title">欢迎登录</div>
<el-form ref="ruleFormRef" :model="form" :rules="loginRules" label-width="0px" style="margin:0px 20px;">
<el-form-item label="" prop="username">
<div class="logininput">
<el-input v-model="form.username" placeholder="请输入用户名">
<template #prepend>
<img src="@/assets/img/username.png" alt="">
</template>
</el-input>
<img class="login-splitline" src="@/assets/img/splitline2.png" style="width:100%;height: 1px;" alt="">
</div>
</el-form-item>
<el-form-item label="" prop="password">
<div class="logininput">
<el-input v-model="form.password" placeholder="请输入密码" type="password">
<template #prepend>
<img src="@/assets/img/password.png" alt="">
</template>
</el-input>
<img class="login-splitline" src="@/assets/img/splitline1.png" style="width:100%;height: 1px;" alt="">
</div>
</el-form-item>
<div class="login-button" @click="submitForm(ruleFormRef)">登录</div>
</el-form>
</div>
</div>
</div>
</template>
<style lang="less" scoped>
.login-box {
width: 100%;
height: 100vh;
background: url(/images/loginbg.png) no-repeat;
background-size: 100% 100%;
display: flex;
justify-content: center;
padding-top: 8%;
.login-container {
.login-title {
display: flex;
align-items: center;
justify-content: center;
height: 60px;
margin-bottom: 100px;
.login-title-left {
transform: rotate(-180deg);
margin-top: 10px;
}
.login-title-text {
text-align: center;
font-size: 35px;
font-weight: bold;
color: #fff;
margin: 0px 30px;
background: linear-gradient(to bottom, #ffffff, #0089ff);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
}
.login-title-right {
margin-bottom: 5px;
}
}
.login-form {
width: 400px;
height: 350px;
margin: 0 auto;
background: #fff;
border-radius: 5px;
padding: 20px;
text-align: center;
background: url(/images/loginform.png) no-repeat;
background-size: 100% 100%;
padding: 40px 20px;
.login-form-title {
font-size: 20px;
font-weight: 600;
color: #fff;
margin-bottom: 20px;
}
.logininput {
position: relative;
height: 40px;
width:100%;
.login-splitline{
position: absolute;
bottom: 0px;
left: 0px;
}
}
}
.login-button{
height: 40px;
line-height: 40px;
font-size: 16px;
color: #fff;
background: url(/images/loginbtn.png) no-repeat;
background-size: 100% 100%;
margin-top: 40px;
cursor: pointer;
}
}
}
</style>
<style>
.logininput .el-input__wrapper{
background-color: transparent;
border: none;
box-shadow: none;
}
.logininput .el-input-group__prepend{
box-shadow: none;
background-color: transparent;
}
.logininput .el-input__inner{
color: #fff;
}
.logininput .el-form-item.is-error .el-input-tag__wrapper, .el-form-item.is-error .el-input-tag__wrapper.is-focus, .el-form-item.is-error .el-input-tag__wrapper:focus, .el-form-item.is-error .el-input-tag__wrapper:hover, .el-form-item.is-error .el-input__wrapper, .el-form-item.is-error .el-input__wrapper.is-focus, .el-form-item.is-error .el-input__wrapper:focus, .el-form-item.is-error .el-input__wrapper:hover, .el-form-item.is-error .el-select__wrapper, .el-form-item.is-error .el-select__wrapper.is-focus, .el-form-item.is-error .el-select__wrapper:focus, .el-form-item.is-error .el-select__wrapper:hover, .el-form-item.is-error .el-textarea__inner, .el-form-item.is-error .el-textarea__inner.is-focus, .el-form-item.is-error .el-textarea__inner:focus, .el-form-item.is-error .el-textarea__inner:hover{
box-shadow: none;
border: none;
box-shadow: none;
}
.login-form .el-form-item__error{
padding-top: 4px ;
}
</style>

View File

@ -156,7 +156,8 @@ function init(){
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100%; width: 100%;
height: calc(100vh - 65px); height: 100vh;
overflow: hidden;
} }
textarea { textarea {
@ -167,7 +168,9 @@ textarea {
} }
.preview { .preview {
width: 100%;
height: 100vh;
flex: 1; flex: 1;
overflow: auto; overflow: hidden;
} }
</style> </style>

View File

@ -0,0 +1,166 @@
<script lang="ts" setup>
import { ref,watch, onMounted,onBeforeUnmount } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import { useRoute, useRouter } from 'vue-router'
import * as VueRouter from 'vue-router'
import { loadModule } from 'vue3-sfc-loader'
import * as Vue from 'vue/dist/vue.esm-bundler.js'
import { i18n } from '@/plugins/vue-i18n'
import ElementPlus from 'element-plus'
import less from 'less'
import defaultTemplate from '@/viewsnew/application/SfcEditor/login.vue?raw'
const route = useRoute()
const router = useRouter()
const sfcCode = ref(defaultTemplate)
const previewContainer = ref(null)
let prevApp = null
// Base64
const convertToBase64 = async (imagePath) => {
try {
//
const resolvedPath = imagePath.replace('@/', '/src/')
const response = await fetch(resolvedPath)
if (!response.ok) throw new Error(`图片加载失败: ${response.status}`)
const blob = await response.blob()
return new Promise((resolve) => {
const reader = new FileReader()
reader.onloadend = () => resolve(reader.result)
reader.readAsDataURL(blob)
})
} catch (error) {
console.error('Base64转换失败:', error.message)
return ''
}
}
const runCode = async () => {
try {
if (prevApp) {
prevApp.unmount()
previewContainer.value.innerHTML = ''
}
const options = {
moduleCache: {
vue: Vue,
'element-plus': ElementPlus,
'vue/dist/vue.esm-bundler.js': Vue,
'vue-router': VueRouter
},
getFile: async (fileName) => {
if (fileName.startsWith('@/')) {
const resolvedPath = fileName.replace('@/', '/src/')
try {
const response = await fetch(resolvedPath)
return { content: await response.text() }
} catch (e) {
console.error(`文件加载失败: ${resolvedPath}`, e)
return { content: '<!-- 文件加载失败 -->' }
}
}
if (fileName === 'dynamic.vue') {
let code = sfcCode.value
// Lessscoped
const lessRegex = /<style\s+.*?lang="less".*?>(.*?)<\/style>/gis
let match
while ((match = lessRegex.exec(code)) !== null) {
const [full, content] = match
try {
const { css } = await less.render(content, {
paths: ['.'], //
filename: 'dynamic.less'
})
code = code.replace(full, `<style>${css}</style>`)
} catch (e) {
console.error('Less编译错误:', e.message)
code = code.replace(full, `<style>/* Less Error: ${e.message} */</style>`)
}
}
//
const imgRegex = /src=['"](.+?\.(png|jpg|jpeg))['"]/gi
let imgMatch
while ((imgMatch = imgRegex.exec(code)) !== null) {
const [full, path] = imgMatch
const base64 = await convertToBase64(path)
code = code.replace(full, `src="${base64}"`)
}
return code
.replace(/<\/script>/g, '<\\/script>')
.replace(/\\\//g, '/')
}
// Less
if (fileName.endsWith('.less')) {
const resolvedPath = fileName.replace('@/', '/src/')
try {
const response = await fetch(resolvedPath)
const content = await response.text()
const { css } = await less.render(content, { filename: fileName })
return { content: css, mediaType: 'text/css' }
} catch (e) {
return { content: `/* Less Error: ${e.message} */`, mediaType: 'text/css' }
}
}
return ''
},
addStyle: (css) => {
const style = document.createElement('style')
style.textContent = css
document.head.appendChild(style)
},
compiledCache: new Map(),
compileTemplate: true
}
const componentModule = await loadModule('dynamic.vue', options)
const component = componentModule.default || componentModule
const dynamicProps = ref({
id: route.query.id,
name: route.query.name,
})
// prevApp = Vue.createApp({
// render: () => Vue.h(component, dynamicProps.value)
// })
prevApp = Vue.createApp({
render: () => Vue.h(component, {
...dynamicProps.value,
router: router,
route: route
})
})
//
prevApp.use(router)
prevApp.use(ElementPlus)
prevApp.use(i18n)
prevApp.mount(previewContainer.value)
} catch (error) {
console.error('运行时错误:', error)
previewContainer.value.innerHTML = `
<div class="error">
<h3>错误</h3>
<pre>${error.message}</pre>
</div>
`
}
}
onMounted(() => {
runCode()
})
onBeforeUnmount(() => {
});
</script>
<template>
<div class="loginBox">
<div ref="previewContainer" class="preview"></div>
</div>
</template>
<style lang="less" scoped>
.loginBox {
width: 100%;
height: 100vh;
}
</style>

View File

@ -73,9 +73,14 @@ function delClick(row){
} }
function preview(row){ function preview(row){
// const route = router.resolve({
// path: '/PreviewSystem',
// query: { id: row.id,name:row.name }
// });
// window.open(route.href, '_blank');
const route = router.resolve({ const route = router.resolve({
path: '/PreviewSystem', path: '/SystemLogin',
query: { id: row.id,name:row.name } query: { id: row.id ,name:row.name}
}); });
window.open(route.href, '_blank'); window.open(route.href, '_blank');
} }

View File

@ -162,7 +162,7 @@ onBeforeMount(() => {
:download-status="downloadStatus" :download-status="downloadStatus"
></dv-preview> ></dv-preview>
<form-create v-if="isFormCreate" :moduleInfo="moduleInfo"></form-create> <form-create v-if="isFormCreate" :moduleInfo="moduleInfo"></form-create>
<Navbar v-if="isNavbar" :isFixed="true" :applicationId="applicationId" <Navbar class="navbarpreview" v-if="isNavbar" :isFixed="true" :applicationId="applicationId"
:menuList="menuList" :projectId="projectId" :projectName="projectInfo.name" :isExecuteEvent="isExecuteEvent"></Navbar> :menuList="menuList" :projectId="projectId" :projectName="projectInfo.name" :isExecuteEvent="isExecuteEvent"></Navbar>
</div> </div>
</div> </div>
@ -185,6 +185,11 @@ onBeforeMount(() => {
position: relative; position: relative;
z-index:1; z-index:1;
} }
.navbarpreview{
width: calc(100% - 260px);
height: calc(100vh - 60px);
// overflow: hidden;
}
</style> </style>
<style> <style>
.ed-message-box{ .ed-message-box{

View File

@ -344,7 +344,6 @@ function addtable(){
depttitle.value = '新增部门' depttitle.value = '新增部门'
deptdialog.value = true deptdialog.value = true
} }
function handleClose() { function handleClose() {
ruleFormRef.value?.resetFields(); ruleFormRef.value?.resetFields();
dialogVisible.value = false; dialogVisible.value = false;
@ -353,8 +352,13 @@ function depthandleClose() {
deptFormRef.value?.resetFields(); deptFormRef.value?.resetFields();
deptdialog.value = false deptdialog.value = false
} }
function formatDateTime(dateTimeStr:any){ function formatDateTime(dateArray:any){
return dateTimeStr.replace('T', ' '); if (!Array.isArray(dateArray) || dateArray.length < 6) return 'Invalid Date'
const pad = (n: number) => n.toString().padStart(2, '0')
return `${dateArray[0]}-${pad(dateArray[1])}-${pad(dateArray[2])} ` +
`${pad(dateArray[3])}:${pad(dateArray[4])}:${pad(dateArray[5])}`
} }
</script> </script>
<template> <template>
@ -431,7 +435,7 @@ function formatDateTime(dateTimeStr:any){
<el-table-column prop="lastmodifier" label="最近修改者"/> <el-table-column prop="lastmodifier" label="最近修改者"/>
<el-table-column prop="lastmodifydate" label="最近修改日期" width="170"> <el-table-column prop="lastmodifydate" label="最近修改日期" width="170">
<template #default="scope"> <template #default="scope">
<span>{{formatDateTime(scope.row.lastmodifydate)}}</span> <span v-if="scope.row.lastmodifydate !== ''">{{formatDateTime(scope.row.lastmodifydate)}}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column fixed="right" label="操作" width="80"> <el-table-column fixed="right" label="操作" width="80">

View File

@ -207,8 +207,13 @@ function handleClose() {
ruleFormRef.value?.resetFields(); ruleFormRef.value?.resetFields();
dialogVisible.value = false; dialogVisible.value = false;
} }
function formatDateTime(dateTimeStr:any){ function formatDateTime(dateArray:any){
return dateTimeStr.replace('T', ' '); if (!Array.isArray(dateArray) || dateArray.length < 6) return 'Invalid Date'
const pad = (n: number) => n.toString().padStart(2, '0')
return `${dateArray[0]}-${pad(dateArray[1])}-${pad(dateArray[2])} ` +
`${pad(dateArray[3])}:${pad(dateArray[4])}:${pad(dateArray[5])}`
} }
function setisValid(row:any){ function setisValid(row:any){
tableloading.value = true tableloading.value = true
@ -299,7 +304,7 @@ function menuChange(data: any, ids: any) {
<el-table-column prop="lastmodifier" label="最近修改者" width="120"/> <el-table-column prop="lastmodifier" label="最近修改者" width="120"/>
<el-table-column prop="lastmodifydate" label="最近修改日期" width="170"> <el-table-column prop="lastmodifydate" label="最近修改日期" width="170">
<template #default="scope"> <template #default="scope">
<span>{{formatDateTime(scope.row.lastmodifydate)}}</span> <span v-if="scope.row.lastmodifydate">{{formatDateTime(scope.row.lastmodifydate)}}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column fixed="right" label="操作" width="100"> <el-table-column fixed="right" label="操作" width="100">

View File

@ -254,8 +254,12 @@ function handleCurrentChange(val: number){
currentPage.value = val currentPage.value = val
queryuserinfo() queryuserinfo()
} }
function formatDateTime(dateTimeStr:any){ function formatDateTime(dateArray:any){
return dateTimeStr.replace('T', ' '); if (!Array.isArray(dateArray) || dateArray.length < 6) return 'Invalid Date'
const pad = (n: number) => n.toString().padStart(2, '0')
return `${dateArray[0]}-${pad(dateArray[1])}-${pad(dateArray[2])} ` +
`${pad(dateArray[3])}:${pad(dateArray[4])}:${pad(dateArray[5])}`
} }
function setisValid(row:any){ function setisValid(row:any){
const params = { const params = {