本文介绍pywebview+vue实现一个系统的登录页面,效果图如下:
在这里插入图片描述
在这里插入图片描述

一、python代码

创建test_pywebview.py文件

import webview

def on_closed():
    print('pywebview window is closed')

def on_closing():
    print('pywebview window is closing')


def on_shown():
    print('pywebview window shown')


def on_loaded():
    print('DOM is ready')


class Api:
    def select_dir(self):  # 选择目录
        result = window.create_file_dialog(webview.FOLDER_DIALOG)
        print(result)
        return result[0] if result else ''

    def select_file(self):  # 选择文件
        file_types = ('Image Files (*.bmp;*.jpg;*.gif;*.png)', 'All files (*.*)')
        result = window.create_file_dialog(webview.OPEN_DIALOG, allow_multiple=True, file_types=file_types)
        print(result)
        return result[0] if result else ''

    def check_login(self, user, pwd):  # 用户登录接口
        print(user, pwd)
        if user != 'test' or pwd != 'test':
            return {'code': '4103', 'msg': '用户名或密码错误'}
        import time
        time.sleep(1)

        groups = {"首页": [], "业务菜单": ["3D模型", "画图展示", "业务3"], "系统设置": ["用户管理", "系统日志"]}
        roles = {"首页": ["读"], "3D模型": ["读", "写"], "业务2": ["读", "写"], "业务3": ["读", "写"],
                 "用户管理": ["读", "写"], "系统日志": ["读", "写"]}

        return {'code': '0', 'data': {'groups': groups, 'roles': roles}, 'msg': 'ok'}


if __name__ == '__main__':
    chinese = {
        'global.quitConfirmation': u'确定关闭?',
    }

    api = Api()
    window = webview.create_window(
        title='pywebview+vue实现系统登录',
        url='static',
        width=900,
        height=620,
        resizable=True,  # 固定窗口大小
        text_select=False,  # 禁止选择文字内容
        confirm_close=True,  # 关闭时提示
        js_api=api, # api中定义供html调用的函数
        min_size=(900, 620) # 设置窗口最小尺寸
    )

	# 添加监听窗口事件
    window.closed += on_closed
    window.closing += on_closing
    window.shown += on_shown
    window.loaded += on_loaded

	# 启动窗口
    webview.start(localization=chinese, http_server=True, debug=True)

代码里面有两个注意的地方:

  • html编译的代码需要放到static目录,test_pywebview.py与static在同一级目录
    在这里插入图片描述

  • create_window指定url参数时,python需要运行http服务,http_server=True时启动webview内置服务

二、html代码

创建login.vue文件

<template>
	<div class="login-container">
		<el-col :span="8" :offset="8" class="login-panel">
			<p class="login-title">Vue前端页面</p>
			<el-form ref="form" :model="form" label-width="80px">
				<el-form-item label="账号">
					<el-input v-model="form.username"><i slot="prefix" class="icon_username"></i></el-input>
				</el-form-item>
				<el-form-item label="密码">
					<el-input type="password" v-model="form.password"><i slot="prefix" class="icon_password"></i></el-input>
				</el-form-item>
				<el-form-item>
					<el-checkbox v-model="form.record">记住密码</el-checkbox>
					<label class="" v-on:click="showMessage('请联系公司的管理帮忙重置密码!');">忘记密码?</label>
				</el-form-item>
				<el-form-item>
					<el-button class="btn-login" @click="login">登录</el-button>
				</el-form-item>
			</el-form>
		</el-col>
	</div>
</template>

<script>
	export default {
		name: 'login',
		props: {
			msg: String
		},
		components: {

		},
		data() {
			return {
				form: {
					username: '',
					password: '',
					record: false
				}
			}
		},
		mounted: function() {
			window.addEventListener('pywebviewready', this.handlePywebview, true)
			this.form.record = localStorage.getItem('record') == 'true' ? true : false;
			if (this.form.record) {
				this.form.username = localStorage.getItem('username');
			}
			this.autoLogin();
		},
		beforeDestroy() {
			window.removeEventListener('pywebviewready', this.handlePywebview, true)
		},
		methods: {
			handlePywebview() {
				console.log('home-------------pywebview is ready, handlePywebview');
			},
async login() {
				if (this.form.username == "" || this.form.password == "") {
					this.$message({
						message: '请输入用户名和密码',
						type: 'warning'
					});
				} else {
			pywebview.api.check_login(this.form.username, this.form.password).then((response) => {
						//alert(response);
						if (response.code == '0') {
							localStorage.setItem('record', this.form.record);
							localStorage.setItem('username', this.form.username);
							this.$store.commit('setData', {
								'access_token': this.form.username,
								'userInfo': this.form.username,
								'groups': response.data.groups,
								'roles': response.data.roles,
							});
							this.$router.push('/home');
							this.form.password = '';
						} else {
							this.$message({
								message: response.msg,
								type: 'warning'
							});
						}
					});
				}
			}
		}
	}
</script>

<style lang="scss" scoped>
	$loginColor: #37637e;

	.login-container {
		position: fixed;
		width: 100%;
		height: 100%;
		top: 0;
		left: 0;
		//background: url("../assets/images/brd-img.png") no-repeat center;
		background-size: 100%;

		.el-form {
			padding-right: 40px;

			.el-form-item__content {
				.yzmcode {
					width: 235px;
				}

				.el-button {
					display: block;
					width: 100%;
				}
			}
		}

		.icon_username {
			//background:url("../assets/images/icon-yhm.png") no-repeat;
		}

		.icon_password {
			//background:url("../assets/images/icon-mm.png") no-repeat;
		}

		.icon_password,
		.icon_yzm,
		.icon_username {
			position: absolute;
			width: 13px;
			height: 13px;
			top: 14px;
		}

		.login-panel {
			position: absolute;
			width: 25%;
			max-width: 480px;
			min-width: 425px;
			height: 515px;
			background-color: #dbefff;
			border-radius: 10px;
			top: 0;
			bottom: 0;
			right: 37%;
			margin: auto;

			.login-title {
				font-family: MicrosoftYaHei;
				font-size: 24px;
				color: $loginColor;
				text-align: center;
				margin: 40px 0 30px;
			}

			.yzmContainer {
				position: absolute;
				height: 40px;
				width: 100px;
				right: 20px;
				top: 0;
				cursor: pointer;
			}

			.form-group {
				width: 350px;
				margin: 0 auto 10px;
				height: 38px;
				line-height: 38px;

				.form-control {
					border-radius: 5px;
					padding-left: 38px;
					height: 38px;
					line-height: 38px;
					font-size: 16px;
				}

				#username {
					//background: url("../assets/images/icon-yonghu.png") no-repeat 10px center;
				}

				#password {
					//background: url("../assets/images/icon-mima.png") no-repeat 10px center;
				}
			}

			.btn-login {
				width: 350px;
				height: 38px;
				line-height: 38px;
				text-align: center;
				border-radius: 20px;
				background-color: #b9ba5f;
				padding: 0;
				margin: 30px auto 15px;
				cursor: pointer;
			}

			.form-check {
				width: 350px;
				margin: 0 auto;

				label {
					cursor: pointer;

					.text {
						margin: 0 0 0 5px;
					}

					font-size: 16px;
					color: #999;

					&:hover {
						color: $loginColor;
					}
				}

				.form-check-input {
					width: 20px;
					height: 20px;
					border: solid 1px $loginColor;
					top: -1px;
				}
			}
		}
	}
</style>

通过pywebview.api.check_login(this.form.username, this.form.password).then((response) => {});来调用python接口

三、完整代码路径

python+html桌面应用实例

下一章介绍python+html开发桌面应用程序(三)程序打包和运行遇到的问题

Logo

前往低代码交流专区

更多推荐