最新AI生成视频工具!效果不输快手可灵,CogVideoX下载介绍 - 老艾的AI世界 - 博客园

mikel阅读(192)

来源: 最新AI生成视频工具!效果不输快手可灵,CogVideoX下载介绍 – 老艾的AI世界 – 博客园

要说AI生成视频最火的项目,当属国产的快手可灵了,甚至比OpenAI的Sora还要火,前者还是个ppt,可灵已经在落地公测了,博主在前段时间申请试用通道的时候,竟然排到几十万人开外的位置,好在最后还是拿到了使用资格,还没用上的外国友人只能干着急,在社交媒体发「求求了!」

 

但就在最近,可灵开始收费了,而且年费要大几千,着实有点儿压力~

就在几天前,对标快手可灵的CogVideoX横空出世了,还可以部署到本地电脑使用,从下图可以看到其效果甚至不输快手可灵

 

CogVideoX最新中文版:

百度网盘:https://pan.baidu.com/s/1b2dS7Wj6-yta7xo7NrjihQ?pwd=7hmo

 

CogVideoX的提示词上限为226个token,视频长度为6秒,帧率为8帧/秒,视频分辨率为720*480。用户只需输入一段文字,就能快速生成充满想象力的视频,还可以自由选择生成的视频风格,包括卡通、3D、黑白、油画、电影等,并配上软件自带的音乐

CogVideoX通过融合文本、时间和空间三个维度,实现了高效、连贯的视频生成,并采用DiT架构和优化算法,显著提升了推理速度和生成质量

工作流程

· 数据预处理:将输入的图像或视频数据转换为模型可以处理的格式,将图像切分成固定大小的patches(小块),然后将这些patches转换为特征向量

· 噪声引入:在数据预处理后的特征向量上逐步引入噪声,形成一个噪声增加的扩散过程,这个过程可以视为从原始数据到噪声数据的转换

· 模型训练:使用引入了噪声的特征向量作为输入,训练Transformer模型,模型的目标是学习如何逆转噪声增加的过程,即从噪声数据恢复出原始数据

· 视频生成:在模型训练完成后,通过输入随机生成的噪声和原始数据的映射关系到模型中,经过模型的处理后生成新的图像或视频

使用方法

1.点击软件界面右下角的load按钮,选择项目自带的workflow.json文件并加载

2.在新打开的界面中,输入待生成视频的提示词

3.设置参数(一般保持默认)

4.点击Queue Prompt按钮

稍微等待一下,视频就生成好了,甄嬛传中皇上啃鸡腿这段我怎么没见过?

 

注意事项

①项目安装路径不要包含中文

②推荐使用GTX1070以上显卡运行此项目

③使用过程中若不慎关闭软件后台,请重新打开,并刷新网页

使li标签横向排列的三种方式_li横向排列-CSDN博客

mikel阅读(120)

来源: 使li标签横向排列的三种方式_li横向排列-CSDN博客

一、display:inline

通过把li转换为行内元素实现,行内元素不独占一行,根据内容撑开大小

 

 

 

 

二、float:left

通过让li浮动实现横向排列 ,浮动会使li脱离文本流,且不占位置

 

 

三。通过flex布局实现

首先给父级定义flex,li{ flex:1}的意思为独占父级宽度的n分之1,这里的n取决于li的个数,也就是4分之1

 

 

————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/m0_61685348/article/details/120694044

深入理解 PHP 高性能框架 Workerman 守护进程原理 - Yxh_blogs - 博客园

mikel阅读(118)

来源: 深入理解 PHP 高性能框架 Workerman 守护进程原理 – Yxh_blogs – 博客园

大家好,我是码农先森。

守护进程顾名思义就是能够在后台一直运行的进程,不会霸占用户的会话终端,脱离了终端的控制。相信朋友们对这东西都不陌生了吧?如果连这个概念都还不能理解的话,建议回炉重造多看看 Linux 进程管理相关的基础知识。在我们日常的编程中常见有类似 php think ...php artisan ...php yii ... 等命令启动需要一直执行的任务,都会通过 nohup 挂载到后台保持长期运行的状态。同样在 Workerman 中也是使用类似 php index.php start 的命令来启动进程,但不同的是它不需要利用 nohup 便可以挂载到后台运行。那有些朋友就会好奇它是怎么实现的呢?为了解决朋友们的疑惑,我们今天就重点深入分析一下 Workerman 守护进程的实现原理。

我们先了解一些进程相关的知识:

  • 父进程:父进程是生成其他进程的进程。当一个进程创建了另一个进程时,创建者被称为父进程,而被创建的进程则成为子进程。父进程可以通过进程标识符(PID)来识别它所创建的子进程。
  • 子进程:子进程是由父进程创建的新进程。子进程继承了父进程的一些属性,例如环境变量、文件描述符等。子进程独立于父进程运行,它可以执行自己的代码,并且具有自己的资源和内存空间。
  • 进程组:进程组是一组相关联的进程的集合。每个进程组都有一个唯一的进程组ID(PGID),用于标识该进程组。进程组通常由一个父进程创建,并且包含了与父进程具有相同会话ID(SID)的所有子进程。
  • 会话:会话是一组关联进程的集合,通常由用户登录到系统开始,直至用户注销或关闭终端会话结束,一个会话中的进程共享相同的控制终端。每个会话都有一个唯一的会话ID(SID),用于标识该会话。会话通常包含一个或多个进程组,其中第一个进程组成为会话的主进程组。

这些概念俗称八股文,向来都不怎么好理解,那我们来看个例子。执行了命令 php index.php 便产生了进程 61052「该进程的父进程是 Bash 进程 8243,这里不用管它」,然后通过 Fork 创建了子进程 61053 且其父进程就是 61052,这两个进程拥有共同的进程组 61052 和会话 8243。调用 posix_setsid 函数,将会为子进程 61053 开启新的进程组 61053 和新的会话 61053,这里的会话可以理解为一个新的命令窗口终端。最后子进程 61053 通过 Fork 创建了子进程 61054,进程 61053 升级成了父进程,这里再次 Fork 的原因是要避免被终端控制进程所关联,这个进程 61052 是在终端的模式下创建的,自此进程 61054 就形成了守护进程。

Copy
[manongsen@root phpwork]$ php index.php
[parent] 进程ID: 61052, 父进程ID: 8243, 进程组ID: 61052, 会话ID: 8243 
[parent1] 进程ID: 61052, 父进程ID: 8243, 进程组ID: 61052, 会话ID: 8243 退出了该进程
[child1] 进程ID: 61053, 父进程ID: 61052, 进程组ID: 61052, 会话ID: 8243 
[child1] 进程ID: 61053, 父进程ID: 61052, 进程组ID: 61053, 会话ID: 61053 
[parent2] 进程ID: 61053, 父进程ID: 61052, 进程组ID: 61053, 会话ID: 61053 退出了该进程
[child2] 进程ID: 61054, 父进程ID: 61053, 进程组ID: 61053, 会话ID: 61053 保留了该进程

[manongsen@root phpwork]$ ps aux | grep index.php
root             66064   0.0  0.0 408105040   1472 s080  S+   10:00下午   0:00.00 grep index.php
root             61054   0.0  0.0 438073488    280   ??  S    10:00下午   0:00.00 php index.php

上面举例的进程信息,正是这段代码运行所产生的。如果看了这段代码且细心的朋友,会发现为什么 posix_setsid 这个函数不放在第一次 Fork 前调用,而在第二次 Fork 前调用呢,这样的话就不用 Fork 两次了?原因是组长进程是不能创建会话的,进程组ID 61052 和进程ID 61052 相同「即当前进程则为组长进程」,所以需要子进程来创建新的会话,这一点需要特别注意一下。

Copy
<?php

function echoMsg($prefix, $suffix="") {
    // 进程ID
    $pid = getmypid(); 
    // 进程组ID
    $pgid = posix_getpgid($pid);
    // 会话ID
    $sid = posix_getsid($pid); 
    // 父进程ID
    $ppid = posix_getppid();

    echo "[{$prefix}] 进程ID: {$pid}, 父进程ID: {$ppid}, 进程组ID: {$pgid}, 会话ID: {$sid} {$suffix}" . PHP_EOL;
}

// [parent] 进程ID: 61052, 父进程ID: 8243, 进程组ID: 61052, 会话ID: 8243
echoMsg("parent");

// 第一次 Fork 进程  
$pid = pcntl_fork();
if ( $pid < 0 ) {
    exit('fork error');
} else if( $pid > 0 ) {
    // [parent1] 进程ID: 61052, 父进程ID: 8243, 进程组ID: 61052, 会话ID: 8243 退出了该进程
    echoMsg("parent1", "退出了该进程");
    exit;
}

// 创建的 子进程ID 为 61053 但 进程组、会话 还是和父进程是同一个
// [child1] 进程ID: 61053, 父进程ID: 61052, 进程组ID: 61052, 会话ID: 8243 
echoMsg("child1");

// 调用 posix_setsid 函数,会创建一个新的会话和进程组,并设置 进程组ID 和 会话ID 为该 进程ID
if (-1 === \posix_setsid()) {
    throw new Exception("Setsid fail");
}

// 现在会发现 进程组ID 和 会话ID 都变成了 61053 在这里相当于启动了一个类似 Linux 终端下的会话窗口
// [child1] 进程ID: 61053, 父进程ID: 61052, 进程组ID: 61053, 会话ID: 61053 
echoMsg("child1");

// 第二次 Fork 进程
// 这里需要二次 Fork 进程的原因是避免被终端控制进程所关联,这个进程 61052 是在终端的模式下创建的
// 需要脱离这个进程 61052 以确保守护进程的稳定
$pid = pcntl_fork();
if ( $pid  < 0 ){
    exit('fork error');
} else if( $pid > 0 ) {
    // [parent2] 进程ID: 61053, 父进程ID: 61052, 进程组ID: 61053, 会话ID: 61053 退出了该进程
    echoMsg("parent2", "退出了该进程");
    exit;
}

// 到这里该进程已经脱离了终端进程的控制,形成了守护进程
// [child2] 进程ID: 61054, 父进程ID: 61053, 进程组ID: 61053, 会话ID: 61053 保留了该进程
echoMsg("child2", "保留了该进程");

sleep(100);

有时间的朋友最好自行执行代码并分析一遍,会有不一样的收获。这里假装你已经实践过了,这下我们来看 Workerman 的 Worker.php 文件中 554 行的 runAll 方法中的 static::daemonize() 这个函数,实现的流程逻辑和上面的例子几乎一样。不过这里还使用了 umask 这个函数,其主要的作用是为该进程所创建的文件或目录赋予相应的权限,保证有权限操作文件或目录。

Copy
// workerman/Worker.php:554
/**
 * Run all worker instances.
 * 运行进程
 * @return void
 */
public static function runAll()
{
    static::checkSapiEnv();
    static::init();
    static::parseCommand();
    static::lock();
    // 创建进程并形成守护进程
    static::daemonize();
    static::initWorkers();
    static::installSignal();
    static::saveMasterPid();
    static::lock(\LOCK_UN);
    static::displayUI();
    static::forkWorkers();
    static::resetStd();
    static::monitorWorkers();
}

// workerman/Worker.php:1262
/**
 * Run as daemon mode.
 * 使用守护进程模式运行
 * @throws Exception
 */
protected static function daemonize()
{
	// 判断是否已经是守护状态、以及当前系统是否是 Linux 环境
    if (!static::$daemonize || static::$_OS !== \OS_TYPE_LINUX) {
        return;
    }
    
    // 设置 umask 为 0 则当前进程创建的文件权限都为 777 拥有最高权限
    \umask(0);
    
    // 第一次创建进程
    $pid = \pcntl_fork();
    if (-1 === $pid) {
    	// 创建进程失败
        throw new Exception('Fork fail');
    } elseif ($pid > 0) {
    	// 主进程退出
        exit(0);
    }

	// 子进程继续执行...
    // 调用 posix_setsid 函数,可以让进程脱离父进程,转变为守护进程
    if (-1 === \posix_setsid()) {
        throw new Exception("Setsid fail");
    }

	// 第二次创建进程,在基于 System V 的系统中,通过再次 Fork 父进程退出
	// 保证形成的守护进程,不会成为会话首进程,不会拥有控制终端
    $pid = \pcntl_fork();
    if (-1 === $pid) {
    	// 创建进程失败
        throw new Exception("Fork fail");
    } elseif (0 !== $pid) {
    	// 主进程退出
        exit(0);
    }

    // 子进程继续执行...
}

守护进程也是 Workerman 中重要的一部分,它保障了 Workerman 进程的稳定性。不像我们通过 nohup 启动的命令,挂起到后台之后,有时还神不知鬼不觉的就挂了,朋友们或许都有这样的经历吧。当然在市面上也有一些开源的守护进程管理软件,比如 supervisor 等,其次还有人利用会话终端 screen、tmux 等工具来实现。其实守护进程的实现方式有多种多样,我们这里只是为了分析 Workerman 中守护进程的实现原理,而引出了在 PHP 中实现守护进程模式的例子,希望本次的内容能对你有所帮助。

感谢大家阅读,个人观点仅供参考,欢迎在评论区发表不同观点。

【干货】ThinkPHP6对接微信扫码登录_thinkphp6 微信扫码登陆-CSDN博客

mikel阅读(121)

来源: 【干货】ThinkPHP6对接微信扫码登录_thinkphp6 微信扫码登陆-CSDN博客

在近几年的互联网网站中,使用微信登录的场景可是越来越多。据统计2020年,全球微信高达11亿,也确实如此,微信这个好用的社交工具,可以说小到一个小学生大到你的七大姑八大姨,很多人可能没有QQ,但他一定有微信。所以微信登录是程序员必备的一项工作技能。

微信扫码登录对接ThinkPHP6,话不多说,直接上车。

一、准备资料:

1、访问 https://open.weixin.qq.com/,注册账户。

2、开发者认证:企业。

3、创建一个网站应用:网站域名必须备案(可使用二级域名),获得相应的AppID和AppSecret,申请微信登录且通过审核。

二、接入微信登录步骤:

首先看下微信官网给出的步骤说明:

https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html

第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数;

通过code参数加上AppID和AppSecret等,通过API换取access_token;

通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。

三、接入微信登录实操环节:

1、放好微信登录图标,并添加链接。
比如链接到www.a,com/index/user/weixindenglu。下面我们看下weixindenglu方法代码。

public function weixindenglu(){

$appid=’wx868f988d79a4f2bb’;

$redirect_uri=urldecode(‘http://www.dongpaiweb.cn/index/index/weixin.html’);

$url=’https://open.weixin.qq.com/connect/qrconnect?appid=’.$appid.’&redirect_uri=’.$redirect_uri.’&response_type=code&scope=snsapi_login&state=STATE#wechat_redirect’;

header(“location:”.$url);

}

这个时候我们点击微信小图标就会出现扫码的界面。拿出手机赶紧微信扫码。

(注意:$redirect_uri是我们的回调地址,意思是用户微信扫码后的处理地址)

2、获得用户的code。
微信扫码后就跳转到了上面定义的回调地址weixin方法。我们看下weixin方法代码:

public function weixin(){
$code=input(‘get.code’);
}

code获取很简单,我们看下打印效果:

3、获得Access Token 和openid,我们在weixin()方法中继续添加代码:

public function weixin(){
$code=input(‘get.code’);
$appid=’wx868f988d79a4f25b’;
$appsecret=’82b426f2882b6a1398b8312cc1de037b’;
$url=’https://api.weixin.qq.com/sns/oauth2/access_token?appid=’.$appid.’&secret=’.$appsecret.’&code=’.$code.’&grant_type=authorization_code’;

//json对象变成数组
$res=json_decode(file_get_contents($url),true);
$access_token=$res[‘access_token’];
$openid=$res[‘openid’];
}

这样我们就获取到了access_token和openid,我们看下打印效果:

5、获取用户全部信息,我们在weixin()方法中继续添加代码:

public function weixin(){

$code=input(‘get.code’);
$appid=’wx868f988d79a4f25b’;
$appsecret=’82b426f2882b6a1398b8312cc1de037b’;
$url=’https://api.weixin.qq.com/sns/oauth2/access_token?appid=’.$appid.’&secret=’.$appsecret.’&code=’.$code.’&grant_type=authorization_code’;

//json对象变成数组

$res=json_decode(file_get_contents($url),true);
$access_token=$res[‘access_token’];
$openid=$res[‘openid’];

$urlyonghu=’https://api.weixin.qq.com/sns/userinfo?access_token=’.$access_token.’&openid=’.$openid;
$user=json_decode(file_get_contents($urlyonghu),true);
print_r($user);

}

这样我们就获取了用户的昵称、地址、头像等信息,看下打印效果:
在我们获取用户微信信息后,我们就可以整理数据入库了。

如果是用户第一次登录,我们可以设置绑定手机号的界面,绑定手机号后即算是注册成功。如果我们检测到已经绑定手机号,即代表登录成功跳转到成功界面。

以上就是ThinkPHP6对接微信扫码登录的操作步骤。加薪升职,赶紧get此技能!
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/wang_xiaoshen/article/details/106709083

C#/.NET/.NET Core优秀项目和框架2024年7月简报 - 追逐时光者 - 博客园

mikel阅读(135)

来源: C#/.NET/.NET Core优秀项目和框架2024年7月简报 – 追逐时光者 – 博客园

前言

公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的介绍、功能特点、使用方式以及部分功能截图等(打不开或者打开GitHub很慢的同学可以优先查看公众号推文,文末一定会附带项目和框架源码地址)。注意:排名不分先后,都是十分优秀的开源项目和框架,每周定期更新分享。

简报GitHub开源地址:https://github.com/YSGStudyHards/DotNetGuide/blob/main/docs/DotNet/DotNetProjectMonthly.md

优秀项目和框架精选:https://github.com/YSGStudyHards/DotNetGuide/blob/main/docs/DotNet/DotNetProjectPicks.md

QrCodeGenerator

WPF UI

IoTClient

N_m3u8DL-RE

SuperShortLink

Dommel

Flurl

  • 项目简介: Flurl是一个集现代性、流畅性、异步性、可测试性、可移植性于一身的URL构建器与HTTP客户端库。它提供了简洁的API,使得HTTP请求的发送与URL的构建变得极为简单与直观。无论是构建复杂的URL路径,还是设置查询参数、请求头或认证信息,Flurl都能以几乎零学习成本的方式实现。
  • 项目源码地址: https://github.com/tmenier/Flurl
  • 公众号详细介绍: https://mp.weixin.qq.com/s/C8dgCdgd5nwLeZvirSqNDw

DBCHM

ML.NET

  • 项目简介: 一个.NET开源、免费、跨平台(支持Windows、Linux、macOS多个操作系统)的机器学习框架,ML.NET 允许开发人员在其 .NET 应用程序中轻松构建、训练、部署和使用自定义模型,而无需具备开发机器学习模型的专业知识或使用 Python 或 R 等其他编程语言的经验。该框架提供从文件和数据加载的数据。数据库,支持数据转换,并包含许多机器学习算法。
  • 项目源码地址: https://github.com/dotnet/machinelearning
  • 公众号详细介绍: https://mp.weixin.qq.com/s/TMC6Dzk-k_Xs13THNNhbbA

Ant Design Blazor

ShardingCore

  • 项目简介: ShardingCore是一款开源、简单易用、高性能、普适性,针对EF Core生态下的分表分库的扩展解决方案,支持EF Core2+的所有版本,支持EF Core2+的所有数据库、支持自定义路由、动态路由、高性能分页、读写分离的一款EF Core拓展程序包,一款零依赖第三方组件的扩展。
  • 项目源码地址: https://github.com/dotnetcore/sharding-core
  • 公众号详细介绍: https://mp.weixin.qq.com/s/skI0O03jvhc7hdCwkdZbjw

Terminal.Gui

BootstrapAdmin

DotNetGuide技术社区交流群

  • DotNetGuide技术社区是一个面向.NET开发者的开源技术社区,旨在为开发者们提供全面的C#/.NET/.NET Core相关学习资料、技术分享和咨询、项目框架推荐、求职和招聘资讯、以及解决问题的平台。
  • 在DotNetGuide技术社区中,开发者们可以分享自己的技术文章、项目经验、学习心得、遇到的疑难技术问题以及解决方案,并且还有机会结识志同道合的开发者。
  • 我们致力于构建一个积极向上、和谐友善的.NET技术交流平台。无论您是初学者还是有丰富经验的开发者,我们都希望能为您提供更多的价值和成长机会。

.NET 与 LayUI 实现高效敏捷开发框架 - 小码编匠 - 博客园

mikel阅读(171)

来源: .NET 与 LayUI 实现高效敏捷开发框架 – 小码编匠 – 博客园

前言

WaterCloud 是一个集成了 LayUI 的高效敏捷开发框架,专为 .NET 开发者设计。

它不仅支持多种 .NET 版本(.NET 4.5、.NET Core 3.1、.NET 5、.NET 6),还内置了丰富的功能,如权限管理、流程表单设计以及多数据库支持下的多租户架构。使用了 ORM(SQLSugar 和 Chloe ) 能够轻松应对复杂的数据处理需求。

WaterCloud 基于ASP.NET 6.0 MVC + API + SQLSugar + LayUI的框架,帮我们解决.NET 开发中的重复工作,提升开发效率。

该框架采用了主流的架构模式,易于学习与使用,有效降低了学习成本,欢迎有需求的小伙伴们来试用!

框架介绍

.NET 和 LayUI 集成的最佳实践;

敏捷开发优选框架,自带权限包含字段、数据权限,自带流程表单设计,基于多数据库的多租户等;

项目版本包含.NET 4.5、.NET Core 3.1、.NET 5、.NET 6;

ORM 包含SqlSugar 和 Chloe;

框架特点

  • 完全开源: 源代码开放,便于二次开发和定制。
  • 主流技术栈: 支持 ASP.NET 6.0、LayUI、SqlSugar 等技术。
  • 多数据库兼容: 支持 SQL Server、MySQL 等多种数据库。
  • 模块化设计: 层次结构清晰,便于维护和扩展。
  • 内置功能: 包括权限管理、数据权限控制、代码生成器等企业级功能。
  • 权限管理: 基于 RBAC 的精细权限控制,覆盖从菜单到字段级别的访问控制。
  • 数据权限: 精细化的数据权限管理,确保数据安全。
  • 表单设计器: 提供直观的拖拽式表单设计工具。
  • 流程设计器: 动态设计工作流程,灵活调整业务逻辑。
  • 内容管理: 集成 wangEditor 编辑器,方便内容编辑。
  • 文件管理: 支持文件上传与下载功能。
  • 响应式布局: 支持多种设备访问,包括 PC、平板、手机等。
  • 实用工具: 封装了日志记录、缓存管理、数据验证等功能。
  • 多租户支持: 基于 Database 的多租户功能。
  • 定时任务: 支持基于 Quartz 的定时任务,具备集群能力。
  • 广泛的适用性: 可用于开发OA、ERP、BPM、CRM、WMS、TMS、MIS、BI、电商、物流、快递、教务管理系统等各类管理软件。

框架技术栈

前端技术

1、JavaScript 框架

  • JQuery 3.4.1
  • LayUI
  • LayUI mini (开源)

2、图标

  • Font Awesome 4.7.0
  • LayUI 自带图标

3、控件

  • 客户端验证: LayUI verify
  • 富文本编辑器: wangEditor (开源), LayUI editor
  • 文件上传: LayUI upload
  • 动态页签: LayUI mini miniTab
  • 数据表格: LayUI table, soul-table (已实现后端筛选)
  • 下拉选择框: LayUI select, xmselect
  • 树结构控件: LayUI dtree
  • 树状表格: treetable-lay (兼容 soul-table 组件,修复了固定列等 BUG)
  • 穿梭框: LayUI transfer
  • 日期控件: LayUI laydate
  • 图标选择: LayUI IconPicker
  • 省市区选择: LayUI layarea

4、页面布局

  • LayUI
  • LayUI mini

5、图表插件

  • echarts

后端技术

  • 核心框架: ASP.NET 6.0, WEB API
  • 定时任务: QuartZ (支持 web 控制)
  • 持久层框架SqlSugar (支持多种数据库, 复杂查询, 多租户, 分库分表等);Chloe (支持多种数据库, 复杂查询, 稳定)
  • 安全支持: 过滤器, Sql 注入防护, 防止请求伪造
  • 服务端验证: 实体模型验证
  • 缓存框架: Redis/Memory (支持单点登录控制)
  • 消息队列: RabbitMQ
  • 事件总线: Jaina
  • 日志管理: 日志记录, 登录日志, 操作日志
  • 工具类: MiniExcel, Newtonsoft.Json, 验证码生成, 通用公共类

环境要求

1、VS 2022 及以上版本;

2、ASP.NE 6.0;

3、Mysql 或者 SQL Server 2005及以上版本,database文件夹下有SQL文件可执行;

4、请使用 VS 2022 及以上版本打开解决方案。

5、Redis 和 RabbitMq 在项目文件夹里有

框架演示

1、演示地址http://47.116.127.212:5000/ (登录: admin / 0000; 数据库每两小时恢复一次)

2、在线文档https://gitee.com/qian_wei_hong/WaterCloud/wikis/pages

3、在线项目https://replit.com/@MonsterUncle/WaterCloud

效果页面

1、登录页面

2、首页展示

3、系统管理

4、流程中心

系统还包含了丰富的功能模块,如文件中心、信息中心、内容管理和订单管理等。可以下载源码,并运行体验这些功能。

项目地址

Gitee:https://gitee.com/qian_wei_hong/WaterCloud

最后

如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。

也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!

vue前端自适应布局,一步到位所有自适应 - lgx211 - 博客园

mikel阅读(146)

来源: vue前端自适应布局,一步到位所有自适应 – lgx211 – 博客园

vue前端自适应布局,一步到位所有自适应

页面展示


实现内容

1,左右布局

  • 左侧固定宽带,右侧自适应剩余的宽度。
  • 中间一条分割线,可以拖拉,自适应调整左右侧的宽度。
  • 左侧的高度超长自动出现横向滚动条,左侧宽度超长,自动出现竖向滚动条。

2,上中下布局

  • 最上面的 搜索条件 div 固定占用 100 px 高度,下面的 查询条件 div 固定占用 30 px 高度,最下面的分页固定占用高度,页面剩下的高度自动分配给中间的表格内容。
  • 表格内容高度超过后自动出现竖向滚动条,宽度超出后自动出现横向滚动条。
  • 点击按钮,可以 隐藏/显示 搜索条件 div 里面的内容。
  • 当隐藏 搜索条件 div 里面的内容时,中间表格的高度为:整个页面的高度—操作按钮div的高度—分页div的高度。
  • 当搜索条件 div 里面的内容时,中间表格的高度为:整个页面的高度—搜索条件div的高度—操作按钮div的高度—分页div的高度。

3,分辨率自适应

  • 加载即动态实时计算高度,宽度

实现代码

<template>
  <div class="app-container">
    <div class="left" :style="{ width: leftWidth + 'px' }">
      <div class="right-center-left">
        左边的内容,可以很长很长很长很长很长很长很长很长很长很长很长很长很长很长很长<br />
        1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
        1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
        1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
        1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
        1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
        1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
      </div>
    </div>
    <div class="divider" @mousedown="startDragging"></div>
    <div class="right">
      <div v-if="showDiv1" class="div1">查询条件</div>
      <div class="div2">
        <button @click="toggleDiv1">操作按钮 div1</button>
      </div>
      <div class="div3" :style="{ height: div3Height + 'px' }">
        1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
        1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
        1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
        1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
        1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
        1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />1<br />
      </div>
      <div class="div4">分页</div>
    </div>
  </div>
</template>

<script>
export default {
  name: "AppContainer",
  data() {
    return {
      isDragging: false,
      leftWidth: 200,
      showDiv1: true
    };
  },
  computed: {
    div3Height() {
      const totalHeight = window.innerHeight;
      const div2Height = 30;
      const div4Height = 30;
      const div1Height = this.showDiv1 ? 100 : 0;

      // 计算 div3 的高度
      return totalHeight - div2Height - div4Height - div1Height;
    }
  },
  methods: {
    startDragging(e) {
      this.isDragging = true;
      document.addEventListener("mousemove", this.onDrag);
      document.addEventListener("mouseup", this.stopDragging);
    },
    onDrag(e) {
      if (this.isDragging) {
        const minWidth = 50;
        const maxWidth = window.innerWidth - 50;
        const newLeftWidth = e.clientX;

        if (newLeftWidth > minWidth && newLeftWidth < maxWidth) {
          this.leftWidth = newLeftWidth;
        }
      }
    },
    stopDragging() {
      this.isDragging = false;
      document.removeEventListener("mousemove", this.onDrag);
      document.removeEventListener("mouseup", this.stopDragging);
    },
    toggleDiv1() {
      this.showDiv1 = !this.showDiv1;
    }
  }
};
</script>

<style scoped>
.app-container {
  display: flex;
  height: 100vh;
  overflow: hidden;
}

.left {
  overflow-x: auto;
  overflow-y: auto;
  white-space: nowrap;
  min-width: 90px;
}

.divider {
  width: 5px;
  cursor: ew-resize;
  background-color: #ccc;
}

.right {
  display: flex;
  flex-direction: column;
  height: 100%;
  flex: 1; /* 自动填满剩余宽度 */
}

.div1 {
  height: 100px;
  background-color: #f0f0f0;
}

.div2 {
  height: 30px;
  background-color: #ddd;
}

.div3 {
  overflow-x: auto; /* 添加横向滚动条 */
  overflow-y: auto; /* 添加纵向滚动条 */
  background-color: #f5f5f5;
}

.div4 {
  height: 200px;
  background-color: #ccc;
}
</style>

实现感想

这个功能,从毕业就开始思索,直到八年后的今天成熟完善,真是艰辛也是很不容易。目前市面上没有见过有人实现,很多人都是只言片语的,基本复制下来,无法达到效果。我这个一键复制到自己的项目,就能实现了,中间的坎坷不平,到了完全实现的这一刻,才觉得激动不已。

无任何坑,也没有任何额外的引入,一个普普通通,最简单的vue页面,布局建好,里面的内容就可以自己随意发挥了。

未觉池塘春草梦,阶前梧叶已秋声。记录激动时刻,也造福后来人。

记录Layui-select中的搜索下拉框lay-search相关的使用(对于初次使用是真的难顶)-CSDN博客

mikel阅读(155)

来源: 记录Layui-select中的搜索下拉框lay-search相关的使用(对于初次使用是真的难顶)-CSDN博客

对于一个后端开发人员来说,常用的easyUI,miniUI,bootstrap,layUI等前端整合式的UI框架能很好的提高页面美观程度以及开发效率

我个人在开发中,使用过miniUI,bootstrap,layUI,其中miniUI是在公司开发时公司要求学习使用的,个人写东西还是偏重于layUI和bootstrap,毕竟看着漂亮点.

本次记录的内容是lay-search这个属性在使用时的问题(可能我能力不够,卡了我两个多小时),因为浪费了过多时间,所以记录一下,在我之前有很多类似的文章,但是都很零碎,没有一个比较全的(搜索水平有限)

首先,lay-search这个属性的作用是:将一个<select>标签初始化为可以输入和选择内容,你输入的文字可以自动匹配,类似百度的搜索.

下面首先贴代码:

<form class=”layui-form”>
<div class=”layui-form-item”>
<div class=”layui-inline col-sm-12″>
<select id=”TemplateOptions” name=”effectsType” class=”layui-select” lay-verify=”required” lay-filter=”selectTemplate” lay-search>
<option value=””>实体要素内容选择</option>
</select>
</div>
</div>
</form>
这里,有个问题就出来,很多人写了select标签,也写了lay-search,但是就是不能选择输入,什么原因?

这里就是第一个问题,select中的lay-search这个属性,必须在layui-form标签中才可以生效

如果说没有layui-form包裹,那么你的select仅仅只是一个正常的<select>下拉选择

然后我们option里面的内容,我选择的方式是页面加载就进行查询渲染,不和数据库做实时交互,毕竟数据量不大

我的思路是页面加载–>初始化Layui–>调用Ajax方法请求数据–>在success方法中组装option标签参数–>使用JQuery进行渲染

是不是上面这个方法看着没啥毛病?对啊,确实是没毛病啊,然后我就卡在这里了,<select>标签里面永远没有我的数据,不管我是用id渲染还是用name获取元素去渲染,都没有数据,不管我用append还是add都一样,最后在layui的文档中发现了,让你给这个lay-search以后重新给了数据以后,需要调用layui.form这个对象进行一次调用,进行重新渲染.否则不会生效.

所以我就这样写了:

layui.use([‘element’,’form’], function(){
var $ = layui.JQuery
,element = layui.element; //Tab的切换功能,切换事件监听等,需要依赖element模块
var form = layui.form;
$.ajax({
type: “POST”,
url: prefix + “/*****”,
data: null,
dataType: ‘json’,
success: function(result) {
var datas = “”;
var data = result.data;
for(var i = 0;i<data.length;i++){
var text = data[i].rtContent.replace(/<\/?.+?>/g,””).replace(/ /g,””);
datas += “<option value='”+text+”‘>” + text +”</option>”;
}
$(‘#TemplateOptions’).append(datas);
form.render(‘select’);
},
error: function(error) {
$.modal.alertWarning(“获取模版数据失败”);
}
});
});
在layui这个js模块初始化的时候顺便获取了下数据这里就是调用重新渲染,括号里面写select就是只重新渲染了当前页面的所有select,如果什么都不写就是默认全页面重新渲染

最后,我希望在我选择以后,这个数据要放在其他的地方,或者弹出来等,然后我就很耿直的去和以前纯js开发那样,直接给option里面去拼接了onchange事件,这样的话,选择完不就可以直接拿值了吗?

嘿嘿……怎么可能满足你.事实是,拼接了onchange事件以后,并没有啥卵用,不会其任何作用,你打开他的页面结构你会发现这鬼地方哪来的所谓的option????所以你绑定的东西.并没有啥卵用,那怎么办呢?

 

layUI,bootstrap等UI框架都需要做的一件事,就是事件监听.你需要自己去初始化一个监听事件,这里我并没有了解过为什么这样,听前端朋友说这样写会好一点,安全一点

form.on(‘select(selectTemplate)’,function(data){
console.info(data.value);
})
在刚刚的ajax获取数据的代码下面,layui初始化方法的里面,我加上了这么一行,这样以后,你就可以在你下拉框中的数据确定变动以后,获取到这里的数据.

 

这次的记录就这些,希望以后有人使用这个东西,能花费很少的时间完工
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/Zachariahs/article/details/99823417

使用layui 表格 下拉框 的实现_layui 下拉框-CSDN博客

mikel阅读(129)

1: 想要实现的 效果 :

2:使用 templet 模版 (代码如下 前提 :接口正常 能获取到数据并展示)

table.render({
elem: ‘#munu-table’
, url: ‘xxx.com/xxxx’
,id:”table”

,page:{
limit: 15
, limits: [15, 20, 30, 40, 50, 100, 150, 200, 250, 300, 400, 500, 800, 1000]
// ,curr:localStorage.getItem(‘spgl_curr’) ? localStorage.getItem(‘spgl_curr’) : 1
}
,totalRow: true //开启合计行
, cols: [[
{type: ‘checkbox’, width: 40, sort: true},
{field: ‘id’, width: 140, title: ‘id’,hide:true},
{field: ‘image’, width: 70, title: ‘图片’,templet:function (d) {
return ‘<img class=”productimages” width=”16px” src=’+d.image+’>’;
}},
{field: ‘list_number’, width: 100, title: ‘清单编号’},
{field: ‘storage_id’, width: 100, title: ‘入库编号’},
{field: ‘batch_number’, width: 80, title: ‘批次号’},
{field: ‘sku’, width: 80, title: ‘sku’},
{field: ‘storage_quantity’, width: 90, title: ‘入库数量’},
{field: ‘sample_quantity’, width: 90, title: ‘留样数量’},
{field: ‘actual_packing_quantity’, width: 115, title: ‘实际装箱数量’},
{field: ‘purchaser’, width: 80, title: ‘采购人’},

{field: ‘outbound_date’, width: 100, title: ‘出库日期’},

{field: ‘pending_days’, width: 100, title: ‘待处理天数’},
{field: ‘processing_status’, width: 100, title: ‘处理进度’},
{field: ‘processor’, width: 80, title: ‘处理人’},
{field: ‘created_time’, width: 100, title: ‘创建时间’},
{field: ‘modified_time’, width: 100, title: ‘修改时间’},

{
field: ‘processing_method’,
title: ‘处理方式’,
align: ‘center’,
width: 200,
templet: function (d) {
var selectHtml = ‘<select name=”paid” class=”sel_xlk” lay-filter=”stateSelect” lay-verify=”required” data-state=”‘ + d.paid + ‘” data-value=”‘ + d.id + ‘” >’ +
‘ <option value=”签补协议”>签补协议</option>’ +
‘ <option value=”等待供应商补发数量”>等待供应商补发数量</option>’ +
‘ <option value=”报损”>报损</option>’ +
‘ <option value=”解除协议”>解除协议</option>’ +
‘ </select>’;

return d.processing_method + selectHtml;
}
},

]]
, done: function(res, curr, count) {
console.log(res); // 在控制台打印获取到的数据

$(“.layui-table-body”).css(‘overflow’,’visible’);
$(“.layui-table-box”).css(‘overflow’,’visible’);
$(“.layui-table-view”).css(‘overflow’,’visible’);

var tableElem = this.elem.next(‘.layui-table-view’);
count || tableElem.find(‘.layui-table-header’).css(‘overflow’, ‘auto’);
layui.each(tableElem.find(‘select[name=”paid”]’), function (index, item) {
var elem = $(item);
elem.val(elem.data(‘state’)).parents(‘div.layui-table-cell’).css(‘overflow’, ‘visible’);
});
form.render();//刷新表单

}

});
注意:templet 的用法 在手册中 只是简单的举了几个例子 。

文档:参考链接

3:注意done 里面的回调 :

done: function(res, curr, count) {
console.log(res); // 在控制台打印获取到的数据

$(“.layui-table-body”).css(‘overflow’,’visible’);
$(“.layui-table-box”).css(‘overflow’,’visible’);
$(“.layui-table-view”).css(‘overflow’,’visible’);

var tableElem = this.elem.next(‘.layui-table-view’);
count || tableElem.find(‘.layui-table-header’).css(‘overflow’, ‘auto’);
layui.each(tableElem.find(‘select[name=”paid”]’), function (index, item) {
var elem = $(item);
elem.val(elem.data(‘state’)).parents(‘div.layui-table-cell’).css(‘overflow’, ‘visible’);
});
form.render();//刷新表单

}
layui.each(tableElem.find(‘select[name=”paid”]’) pid 是 field: ‘pid’, 的值。

上面的代码 加上后才能正常的展示 下拉 数据 如果没有 这段代码 点击 下拉图标 不会起作用。

4:修改数据:

form.on(‘select(stateSelect)’, function (data) {//修改类型
let id = data.elem.dataset.value; //当前数据的id
let processing_method = data.elem.value; //当前字段变化的值
// 传值:表单变化后的值传递到后台数据库进行实时修改,例如,根据id修改这条数据的状态。

console.log(id);
console.log(processing_method);

$.ajax({
type: ‘post’,
url:’xxx.com/xxx’, // ajax请求路径
data: {
id: id,
processing_method: processing_method
},
success: function(data){

var data = JSON.parse(data)
layer.msg(data.msg);

// layer.msg(‘修改成功’);

// console.log(data);
//执行重载
//table.reload(‘bizInvoiceTable’);
//window.location.href = Feng.ctxPath + ‘/bizInvoice’
}
});
});

总结: 我遇到最多的问题就是 选择 下拉图标的时候 不能展示下拉的数据 。 所以一定要注意 红色字段。

未解决的问题 : 下拉框会被覆盖 f12 能高亮度找到 但是被表格下面的滑块 覆盖了 。

有滑块的时候 会出现 每列的线格子 会与 tittle 对不齐
————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/qq_51110402/article/details/132511932

layui实现table添加行功能 table里有select可选择可编辑 并且与form表单一起提交数据保存_layuitable 可编辑,有下拉框和输入框-CSDN博客

mikel阅读(154)

来源: layui实现table添加行功能 table里有select可选择可编辑 并且与form表单一起提交数据保存_layuitable 可编辑,有下拉框和输入框-CSDN博客

这个例子中的下拉框是 可选择 并且 可输入的 还有一个下拉框的点击事件 选择一个值的时候 带出后面几列的值
<%@ page language=”java” import=”java.util.*” pageEncoding=”UTF-8″%>
<%@ include file=”/WEB-INF/page/public/tag.jsp”%>
<!DOCTYPE HTML PUBLIC “-//W3C//DTD HTML 4.01 Transitional//EN”>
<html>
<head>
<meta charset=”utf-8″>
<title><jsp:include page=”/WEB-INF/page/public/top_title.jsp”/></title>
<meta name=”renderer” content=”webkit”>
<meta http-equiv=”X-UA-Compatible” content=”IE=edge,chrome=1″>
<meta name=”viewport” content=”width=device-width, initial-scale=1, maximum-scale=1″>
<meta name=”apple-mobile-web-app-status-bar-style” content=”black”>
<meta name=”apple-mobile-web-app-capable” content=”yes”>
<meta name=”format-detection” content=”telephone=no”>
<link rel=”stylesheet” href=”${contextPath}/statics/css/layui.css” media=”all”/>
<style>
        /* 防止下拉框的下拉列表被隐藏—必须设置— 此样式和表格的样式有冲突 如果表格列数太多 会出现错乱的情况 目前我的解决方法是忽略下拉框的美化渲染 <select lay-ignore> */
        .layui-table-cell {
            overflow: visible;
        }
        .layui-table-box {
            overflow: visible;
        }
        .layui-table-body {
            overflow: visible;
        }
        /* 设置下拉框的高度与表格单元相同 */
        td .layui-form-select{
margin-top: -10px;
margin-left: -15px;
margin-right: -15px;
}
    </style>
</head>
<body class=”childrenBody”>
<div  style=”padding:15px;”>
<blockquote class=”layui-elem-quote”>
<span class=”layui-breadcrumb” style=”visibility: visible;”>
<a href=”main.html”>首页</a>
<span lay-separator=””>/</span>
<a href=”${contextPath}/storage/toList”>物料入库</a>
<span lay-separator=””>/</span>
<a><cite>物料入库新增</cite></a> </span>
</blockquote>
<form class=”layui-form” id=”fromId” action=”#”>
  <fieldset class=”layui-elem-field”>
<div style=”padding-top:25px;” class=”layui-field-box”>
  <div class=”layui-form-item”>
<label class=”layui-form-label”>入库单编号</label>
<div class=”layui-input-inline” style=”width:13%”>
  <input type=”text” name=”storagecode” placeholder=”请输入” class=”layui-input” lay-verify=”required”>
</div>
<label class=”layui-form-label”>入库人</label>
<div class=”layui-input-inline” style=”width:13%”>
<input type=”text” name=”storageuser” placeholder=”请输入” class=”layui-input”>
</div>
<label class=”layui-form-label”>仓库</label>
<div class=”layui-input-inline” style=”width:13%”>
<input type=”text” name=”warehouseid” placeholder=”请输入” class=”layui-input”>
</div>
<label class=”layui-form-label”>金额</label>
<div class=”layui-input-inline” style=”width:13%”>
<input type=”text” name=”money” placeholder=”请输入” class=”layui-input”>
</div>
  </div>
  <div class=”layui-form-item”>
    <label class=”layui-form-label”>入库日期</label>
    <div class=”layui-input-inline” style=”width:13%”>
    <input type=”text” name=”storagetime” placeholder=”请选择” class=”layui-input” id=”date”>
    </div>
    <label class=”layui-form-label”>制单人</label>
<div class=”layui-input-inline” style=”width:13%”>
<input type=”text” name=”documentmaker” placeholder=”请输入” class=”layui-input”>
</div>
<label class=”layui-form-label”>供应商</label>
<div class=”layui-input-inline” style=”width:13%”>
<input type=”text” name=”supplier” placeholder=”请输入” class=”layui-input”>
</div>
</div>
</div>
  </fieldset>
  <script type=”text/html” id=”selectTool”>
 <select name=”selectDemo” lay-filter=”selectDemo” lay-search>
<option value=””>请选择或输入</option>
        {{# layui.each(${selectByExample}, function(index, item){ }}
        <option>{{ item.materialcode }}</option>
        {{# }); }}
    </select>
</script>
  <script type=”text/html” id=”toolbarDemo”>
  <div align=”right” class=”layui-btn-container”>
  <button id=”addTable” class=”layui-btn layui-btn-sm layui-btn-normal” lay-event=”add”>添加行</button>
  </div>
</script>
  <script type=”text/html” id=”bar”>
<a class=”layui-btn layui-btn-danger layui-btn-xs” lay-event=”del”>删除</a>
    </script>
<table id=”demo” lay-filter=”tableFilter”></table>
<div class=”layui-form-item”  style=”margin-top: 30px;text-align: center;”>
    <button class=”layui-btn” lay-submit=”” lay-filter=”*”>保存</button>
    <a href=”${contextPath}/storage/toList” class=”layui-btn layui-btn-primary”>返回</a>
</div>
</form>
</div>
<script type=”text/JavaScript” src=”${contextPath}/statics/layui.js”></script>
<script>
layui.use([‘laydate’,’table’,’form’,’JQuery’], function(){
  var table = layui.table,
      form = layui.form,
    laydate = layui.laydate,
    $ = layui.JQuery;
  //时间控件
  laydate.render({
  elem: ‘#date’ //指定元素
  });
  //下拉框监听事件
  form.on(‘select(selectDemo)’, function(data){
//这里是当选择一个下拉选项的时候 把选择的值赋值给表格的当前行的缓存数据 否则提交到后台的时候下拉框的值是空的
var elem = data.othis.parents(‘tr’);
  var dataindex = elem.attr(“data-index”);
  $.each(tabledata,function(index,value){
        if(value.LAY_TABLE_INDEX==dataindex){
        value.materialcode = data.value;
        }
      });
      //这个是根据下拉框选的值 查询后台 带出后面几列的数据并赋值给页面 没有需要的同学忽略掉即可
     if(data.value){ $.ajax({
url:”${contextPath}/storage/toSelect”,
async:true,
type:”post”,
data:{“materialcode”:data.value},
success:function(data){
if(typeof(data) == ‘string’){
data = JSON.parse(data)
}
//给页面赋值
elem.find(“td[data-field=’materialname’]”).children().html(data.data.materialname);
elem.find(“td[data-field=’specifications’]”).children().html(data.data.specifications);
elem.find(“td[data-field=’warehouseid’]”).children().html(data.data.warehouseid);
elem.find(“td[data-field=’warningnumber’]”).children().html(data.data.warningnumber);
elem.find(“td[data-field=’topwarning’]”).children().html(data.data.topwarning);
elem.find(“td[data-field=’unitprice’]”).children().html(data.data.unitprice);
//给表格缓存赋值
$.each(tabledata,function(index,value){
      if(value.LAY_TABLE_INDEX==dataindex){
      value.materialname = data.data.materialname;
      value.specifications = data.data.specifications;
      value.warehouseid = data.data.warehouseid
      value.warningnumber = data.data.warningnumber;
      value.topwarning = data.data.topwarning
      value.unitprice = data.data.unitprice;
      }
     });
}
    });
     }
});
//第一个实例 加载表格
var tableIns = table.render({
 elem: ‘#demo’
 ,toolbar: ‘#toolbarDemo’
 ,defaultToolbar:[]
 ,limit:100
 ,cols: [[ //表头
    {field: ‘materialcode’, title: ‘物料编号’,templet: ‘#selectTool’}
   ,{field: ‘materialname’, title: ‘物料名称’,edit: ‘text’}
   ,{field: ‘number’, title: ‘数量’,edit: ‘text’}
   ,{field: ‘specifications’, title: ‘规格’,edit: ‘text’}
   ,{field: ‘warehouseid’, title: ‘仓库’,edit: ‘text’}
   ,{field: ‘warningnumber’, title: ‘最低库存’,edit: ‘text’}
   ,{field: ‘topwarning’, title: ‘最高库存’,edit: ‘text’}
   ,{field: ‘unitprice’, title: ‘单价’,edit: ‘text’}
   ,{field: ‘subtotal’, title: ‘小计’}
   ,{title: ‘操作’,align:’center’, toolbar: ‘#bar’}
 ]]
,data:[{  “materialcode”: “”
      ,”materialname”: “”
      ,”number”: “”
      ,”specifications”: “”
      ,”warehouseid”: “”
      ,”warningnumber”: “”
      ,”topwarning”: “”
      ,”unitprice”: “”
      ,”subtotal”: “”
    }]
,done: function(res, curr, count){
    //如果是异步请求数据方式,res即为你接口返回的信息。
    //如果是直接赋值的方式,res即为:{data: [], count: 99} data为当前页数据、count为数据总长度
    tabledata = res.data;
    //去掉下拉框的失焦事件 否则在下拉框里输入值 失焦后变回下拉选项里的值了 没有需要的同学忽略掉即可
    $(‘.layui-form-select’).find(‘input’).unbind(“blur”);
    //这里是表格重载的时候 回显下拉框的数据
    $(‘tr’).each(function(e){
    var $cr=$(this);
    var dataindex = $cr.attr(“data-index”);
        $.each(tabledata,function(index,value){
        if(value.LAY_TABLE_INDEX==dataindex){
        $cr.find(‘input’).val(value.materialcode);
        }
       });
      });
        //这里是下拉框输入值改变时触发 给表格缓存赋值 没有需要的同学忽略掉即可
        $(‘.layui-form-select’).find(‘input’).on(“change”,function(e){
        var $cr=$(e.target);
        console.log($cr);
        var dataindex = $cr.parents(‘tr’).attr(“data-index”);
        var selectdata = $cr.val();
            $.each(tabledata,function(index,value){
            if(value.LAY_TABLE_INDEX==dataindex){
            value.materialcode = selectdata;
            }
           });
        });
        //这里是数量的输入事件 计算小计用的 小计 = 数量 X 单价
        var numberelem = $(‘.layui-table-main’).find(“td[data-field=’number’]”);
        var unitpriceelem = $(‘.layui-table-main’).find(“td[data-field=’unitprice’]”);
        numberelem.on(“input”,function(e){
        var $cr=$(e.target);
        var dataindex = $cr.parents(‘tr’).attr(“data-index”);
        var unitprice = $cr.parents(‘tr’).find(“td[data-field=’unitprice’]”).children().html();
        var sub = unitprice*e.target.value;
        $cr.parents(‘tr’).find(“td[data-field=’subtotal’]”).children().html(sub);
        $.each(tabledata,function(index,value){
            if(value.LAY_TABLE_INDEX==dataindex){
            value.subtotal = sub;
            }
           });
        });
        //这里是单价的输入事件 计算小计用的 小计 = 数量 X 单价
        unitpriceelem.on(“input”,function(e){
        var $cr=$(e.target);
        var dataindex = $cr.parents(‘tr’).attr(“data-index”);
        var number = $cr.parents(‘tr’).find(“td[data-field=’number’]”).children().html();
        var sub = number*e.target.value;
        $cr.parents(‘tr’).find(“td[data-field=’subtotal’]”).children().html(sub);
        $.each(tabledata,function(index,value){
            if(value.LAY_TABLE_INDEX==dataindex){
            value.subtotal = sub;
            }
           });
        });
  }
});
var tabledata;
//监听工具条删除按钮
   table.on(‘tool(tableFilter)’, function(obj){
    if(obj.event === ‘del’){
    obj.del();
      };
     }
  );
 //头工具栏添加按钮事件
  table.on(‘toolbar(tableFilter)’, function(obj){
if(obj.event === ‘add’){
tabledata.push({
  “materialcode”: “”
        ,”materialname”: “”
        ,”number”: “”
        ,”specifications”: “”
        ,”warehouseid”: “”
        ,”warningnumber”: “”
    ,”topwarning”: “”
        ,”unitprice”: “”
        ,”subtotal”: “”
          })
      table.reload(‘demo’, {
    data: tabledata
  });
    };
  });
 //提交数据到后台保存
  form.on(‘submit(*)’, function(data){
// console.log(data.elem) //被执行事件的元素DOM对象,一般为button对象
// console.log(data.form) //被执行提交的form对象,一般在存在form标签时才会返回
//  console.log(data.field) //当前容器的全部表单字段,名值对形式:{name: value}
//  console.log(tabledata) //当前容器的全部表单字段,名值对形式:{name: value}
  $.ajax({
url:”${contextPath}/storage/toSave”,
async:true,
type:”post”,
data:$(data.form).serialize()+’&tabledata=’+JSON.stringify(tabledata),
success:function(data){
if(typeof(data) == ‘string’){
data = JSON.parse(data)
}
if(data.code == 0){
layer.msg(data.msg);
window.location.href=”${contextPath}/storage/toList”;
}else{
layer.msg(data.msg);
}
}
      });
  return false; //阻止表单跳转。如果需要表单跳转,去掉这段即可。
});
});
</script>
</body>
</html>
————————————————
                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_26814945/article/details/83275765