layui.prompt 监听回车键来触发确认操作
layer.prompt({
title: '请输入密码:',
formType: 1,
success: function(layero, index){
$(layero).find('.layui-layer-input').prop('autocomplete','new-password').on('keydown',function(e){
if(e.which === 13){
$(layero).find('.layui-layer-btn0').trigger('click');
}
});
},
yes: function(index, layero){
let elem=$(layero).find('.layui-layer-input'), value=elem.val();
if(value==='123456'){
layer.close(index);
layer.msg('密码正确');
}else{
elem.focus();
layer.tips(value===''?'请输入':'密码错误',elem,{tips:1,time:2e3});
}
}
});
传统prompt方法无法监听输入
layer.prompt({
title: '请输入密码:',
formType: 1,
},function(value, index, elem){
console.log(value);
layer.close(index);
});
mysql两表组合查询的一种优化方法
表tab_class为产品与分类对照表,一个产品可能属于多个分类
首页要确保 tab_class 表有 classid和productid 的复合索引
ALTER TABLE tab_class ADD INDEX idx_classid_productid (classid, productid);
JOIN 组合查询:
SELECT `tab_product`.* FROM `tab_product` JOIN `tab_class` ON `tab_product`.`id`=`tab_class`.`productid` WHERE `tab_class`.`classid` IN(3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606) GROUP BY `tab_product`.`id` ORDER BY `id` DESC LIMIT 10;
EXISTS 查询:
SELECT *
FROM `tab_product`
WHERE `id` IN(
SELECT DISTINCT(productid)
FROM tab_class
WHERE classid IN(3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606)
)
ORDER BY `id` DESC LIMIT 10;在CodeIgniter中的写法:
$class_ids = [3593,3594,3595,3596,3597,3598,3599,3600,3601,3602,3603,3604,3605,3606];
$this->db->from('tab_product');
$this->db->where_in('id', "
SELECT DISTINCT(productid)
FROM tab_class
WHERE classid IN (".implode(',', $class_ids).")
");
$this->db->order_by('id', 'DESC');
$this->db->limit(10);
$query = $this->db->get();SELECT DISTINCT(productid) 中的 DISTINCT 可以省略,因为外层的 IN 会自动去重复。但如果结果集比较大还是建议加上。
也可以使用 EXPLAIN 查询两种方法的性能,择优使用
layui多图带预览的上传
<div class="layui-form-item">
<label class="layui-form-label">图片上传</label>
<div class="layui-input-block">
<button type="button" class="layui-btn layui-btn-primary layui-border-blue" id="js-btn-upload"><i class="layui-icon layui-icon-upload"></i> 上传图片</button>
</div>
</div>
<div class="layui-form-item">
<ul id="upload-list" class="upload-list"></ul>
</div>
<script type="text/html" id="upload-tpl">
<li id="js-image-{{ d.index }}">
<div class="layui-progress" lay-filter="progress-{{ d.index }}"><div class="layui-progress-bar" lay-percent=""></div></div>
<em><img src="{{ d.url }}"><a class="layui-btn layui-btn-xs layui-bg-red js-reupload">重新上传</a></em>
<div class="layui-btn-group">
<a class="layui-btn layui-btn-primary layui-btn-sm layui-border-blue js-left"><i class="layui-icon layui-icon-left"></i></a>
<a class="layui-btn layui-btn-primary layui-btn-sm layui-border-red js-delete"><i class="layui-icon layui-icon-delete"></i></a>
<a class="layui-btn layui-btn-primary layui-btn-sm layui-border-blue js-right"><i class="layui-icon layui-icon-right"></i></a>
</div>
<input type="hidden" name="imglist[]">
</li>
</script>
<script>
//上传图片
var uploadInst = layui.upload.render({
elem: '#js-btn-upload', //绑定元素
elemList: $('#upload-list'), // 列表元素对象
url: '<?=site_url('kindeditor/uploadjson?type=image&dir=product')?>',
acceptMime: 'image/jpeg, image/png',
exts: 'jpg|png',
size: 1024,
field: 'imgFile',
multiple: true,
number: 6,
auto: false,
choose: function(obj){
uploadInst.config.elem.next()[0].value = '';
var pics=this.elemList.find('li').length;
if(pics>=this.number || pics+Object.keys(obj.getChooseFiles()).length>this.number){
layer.msg('最多上传6张图片');
return false;
}
// 读取本地文件
var that = this;
obj.preview(function(index, file, result){
var li=$(laytpl($('#upload-tpl').html()).render({index:index,url:result}));
li.find('.layui-progress').show();
li.find('.js-reupload').on('click', function(){
obj.upload(index, file);
$(this).hide();
element.progress('progress-'+ index, '0%');
});
that.elemList.append(li);
element.render('progress'); // 渲染新加的进度条组件
obj.upload(index, file);
});
},
done: function(res, index, upload){ // 成功的回调
var that = this;
if(res.error == 0){ // 上传成功
var li = that.elemList.find('li#js-image-'+ index)
li.find('.layui-progress').remove();
li.find('input').val(res.url);
return;
}
this.error(index, upload);
},
error: function(index, upload){ // 错误回调
var that = this;
var li = that.elemList.find('li#js-image-'+ index);
//显示重传
li.find('.js-reupload').show();
layer.msg('上传失败',{icon:5});
},
progress: function(n, elem, e, index){ // 注意:index 参数为 layui 2.6.6 新增
element.progress('progress-'+ index, n + '%'); // 执行进度条。n 即为返回的进度百分比
}
});
</script>
windows指定图片使用照片查看器打开
常见图片格式在右键》属性》打开方式中即可设置。
如果打开方式中没有"照片查看器",可以在注册表如下路径:
计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Photo Viewer\Capabilities\FileAssociations
新建字符串值,名称如:.webp,数值:PhotoViewer.FileAssoc.Tiff
注意:用Windows照片查看器浏览 webp格式 的图片可能会出现较大色差。
使用ffmpeg下载合并ts视频为mp4
https://www.gyan.dev/ffmpeg/builds/
2、解压后,window dos 进入相应的bin目录
3、运行ffmpeg合并ts文件
ffmpeg -i "d:\下载.m3u8" -c copy "d:\合并.mp4"
出现下面错误时,可加相应参数解决:
Filename extension of 'd:\下载\crypt.key' is not a common multimedia extension, blocked for security reasons.If you wish to override this adjust allowed_extensions, you can set it to 'ALL' to allow all
ffmpeg -allowed_extensions ALL -i "d:\下载.m3u8" -c copy "d:\合并.mp4"
------------------------
关于 IV(初始化向量):
检查您的 M3U8 文件,#EXT-X-KEY 标签中是否包含了 IV 参数(例如 IV=0x1234567890ABCDEF1234567890ABCDEF)。
如果没有指定 IV,FFmpeg 可能会使用默认值(比如序列号或全零)。如果解密后视频花屏或无法播放,可以尝试在 FFmpeg 命令中手动指定 IV(如果已知):
ffmpeg -allowed_extensions ALL -decryption_iv 1234567890ABCDEF1234567890ABCDEF -i "input.m3u8" -c copy "output.ts"
密钥格式:FFmpeg 期望的密钥通常是二进制文件或十六进制字符串。如果您的密钥是 Base64 编码的,需要先解码。可以使用在线 Base64 解码工具,或者使用 Python/Node.js 等脚本语言进行转换
CSS改变png图标颜色
主要用途:改变纯色线描icon小图标颜色
<div class="masked-line"></div>
<style>
.masked-line {
width: 200px;
height: 200px;
background-color: purple; /* 目标颜色 */
-webkit-mask-image: url('your-image.png');
mask-image: url('your-image.png');
}
</style>原图:
![]()
变红
html根据坐标生成百度地图、高德地图导航地址
百度地图
https://map.baidu.com/?latlng=36.683544,117.032171&title=济南市大明湖公园&content=山东省济南市历下区大明湖路271号&autoOpen=true&l=
高德地图
http://ditu.amap.com/regeo?lng=104.06074583530426&lat=30.5379691198173
分别用js、php实现GS84与GCJ02两种坐标系的互转
高德地图: 使用 GCJ-02 坐标系,也称为火星坐标系。它是基于国际标准 WGS-84 坐标系进行加密处理得到的。
百度地图: 采用 BD-09 坐标系,这是在 GCJ-02 基础上进行二次加密而来的,具有更高的安全性和隐私保护。
天地图: 使用 CGCS2000 坐标系,该坐标系与 WGS-84 存在微小偏差,在要求不高的情况下可以直接与 WGS-84 互换使用。
js
/**
* WGS84转GCJ02(火星坐标系)
* @param {number} wgsLon WGS84坐标系的经度
* @param {number} wgsLat WGS84坐标系的纬度
* @returns {Array} GCJ02坐标 [经度, 纬度]
*/
function wgs84ToGcj02(wgsLon, wgsLat) {
const PI = 3.14159265358979324;
const a = 6378245.0;
const ee = 0.00669342162296594323;
if (outOfChina(wgsLat, wgsLon)) {
return [wgsLon, wgsLat];
}
let dLat = transformLat(wgsLon - 105.0, wgsLat - 35.0);
let dLon = transformLon(wgsLon - 105.0, wgsLat - 35.0);
const radLat = wgsLat / 180.0 * PI;
let magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
const sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
const gcjLat = wgsLat + dLat;
const gcjLon = wgsLon + dLon;
return [gcjLon, gcjLat];
}
/**
* GCJ02(火星坐标系)转WGS84
* @param {number} gcjLon GCJ02坐标系的经度
* @param {number} gcjLat GCJ02坐标系的纬度
* @returns {Array} WGS84坐标 [经度, 纬度]
*/
function gcj02ToWgs84(gcjLon, gcjLat) {
const PI = 3.14159265358979324;
const a = 6378245.0;
const ee = 0.00669342162296594323;
if (outOfChina(gcjLat, gcjLon)) {
return [gcjLon, gcjLat];
}
let dLat = transformLat(gcjLon - 105.0, gcjLat - 35.0);
let dLon = transformLon(gcjLon - 105.0, gcjLat - 35.0);
const radLat = gcjLat / 180.0 * PI;
let magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
const sqrtMagic = Math.sqrt(magic);
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
dLon = (dLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
const wgsLat = gcjLat - dLat;
const wgsLon = gcjLon - dLon;
return [wgsLon, wgsLat];
}
function transformLat(x, y) {
let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(y * Math.PI) + 40.0 * Math.sin(y / 3.0 * Math.PI)) * 2.0 / 3.0;
ret += (160.0 * Math.sin(y / 12.0 * Math.PI) + 320 * Math.sin(y * Math.PI / 30.0)) * 2.0 / 3.0;
return ret;
}
function transformLon(x, y) {
let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
ret += (20.0 * Math.sin(6.0 * x * Math.PI) + 20.0 * Math.sin(2.0 * x * Math.PI)) * 2.0 / 3.0;
ret += (20.0 * Math.sin(x * Math.PI) + 40.0 * Math.sin(x / 3.0 * Math.PI)) * 2.0 / 3.0;
ret += (150.0 * Math.sin(x / 12.0 * Math.PI) + 300.0 * Math.sin(x / 30.0 * Math.PI)) * 2.0 / 3.0;
return ret;
}
function outOfChina(lat, lon) {
return lon < 72.004 || lon > 137.8347 || lat < 0.8293 || lat > 55.8271;
}
// 使用示例
// let gcjCoord = wgs84ToGcj02(116.404, 39.915); // WGS84转GCJ02
// let wgsCoord = gcj02ToWgs84(116.404, 39.915); // GCJ02转WGS84
PHP
/**
* WGS84转GCJ02(火星坐标系)
* @param float $wgsLon WGS84坐标系的经度
* @param float $wgsLat WGS84坐标系的纬度
* @return array GCJ02坐标 [经度, 纬度]
*/
function wgs84ToGcj02($wgsLon, $wgsLat) {
$PI = 3.14159265358979324;
$a = 6378245.0;
$ee = 0.00669342162296594323;
if (outOfChina($wgsLat, $wgsLon)) {
return array($wgsLon, $wgsLat);
}
$dLat = transformLat($wgsLon - 105.0, $wgsLat - 35.0);
$dLon = transformLon($wgsLon - 105.0, $wgsLat - 35.0);
$radLat = $wgsLat / 180.0 * $PI;
$magic = sin($radLat);
$magic = 1 - $ee * $magic * $magic;
$sqrtMagic = sqrt($magic);
$dLat = ($dLat * 180.0) / (($a * (1 - $ee)) / ($magic * $sqrtMagic) * $PI);
$dLon = ($dLon * 180.0) / ($a / $sqrtMagic * cos($radLat) * $PI);
$gcjLat = $wgsLat + $dLat;
$gcjLon = $wgsLon + $dLon;
return array($gcjLon, $gcjLat);
}
/**
* GCJ02(火星坐标系)转WGS84
* @param float $gcjLon GCJ02坐标系的经度
* @param float $gcjLat GCJ02坐标系的纬度
* @return array WGS84坐标 [经度, 纬度]
*/
function gcj02ToWgs84($gcjLon, $gcjLat) {
$PI = 3.14159265358979324;
$a = 6378245.0;
$ee = 0.00669342162296594323;
if (outOfChina($gcjLat, $gcjLon)) {
return array($gcjLon, $gcjLat);
}
$dLat = transformLat($gcjLon - 105.0, $gcjLat - 35.0);
$dLon = transformLon($gcjLon - 105.0, $gcjLat - 35.0);
$radLat = $gcjLat / 180.0 * $PI;
$magic = sin($radLat);
$magic = 1 - $ee * $magic * $magic;
$sqrtMagic = sqrt($magic);
$dLat = ($dLat * 180.0) / (($a * (1 - $ee)) / ($magic * $sqrtMagic) * $PI);
$dLon = ($dLon * 180.0) / ($a / $sqrtMagic * cos($radLat) * $PI);
$wgsLat = $gcjLat - $dLat;
$wgsLon = $gcjLon - $dLon;
return array($wgsLon, $wgsLat);
}
function transformLat($x, $y) {
$ret = -100.0 + 2.0 * $x + 3.0 * $y + 0.2 * $y * $y + 0.1 * $x * $y + 0.2 * sqrt(abs($x));
$ret += (20.0 * sin(6.0 * $x * M_PI) + 20.0 * sin(2.0 * $x * M_PI)) * 2.0 / 3.0;
$ret += (20.0 * sin($y * M_PI) + 40.0 * sin($y / 3.0 * M_PI)) * 2.0 / 3.0;
$ret += (160.0 * sin($y / 12.0 * M_PI) + 320 * sin($y * M_PI / 30.0)) * 2.0 / 3.0;
return $ret;
}
function transformLon($x, $y) {
$ret = 300.0 + $x + 2.0 * $y + 0.1 * $x * $x + 0.1 * $x * $y + 0.1 * sqrt(abs($x));
$ret += (20.0 * sin(6.0 * $x * M_PI) + 20.0 * sin(2.0 * $x * M_PI)) * 2.0 / 3.0;
$ret += (20.0 * sin($x * M_PI) + 40.0 * sin($x / 3.0 * M_PI)) * 2.0 / 3.0;
$ret += (150.0 * sin($x / 12.0 * M_PI) + 300.0 * sin($x / 30.0 * M_PI)) * 2.0 / 3.0;
return $ret;
}
function outOfChina($lat, $lon) {
return $lon < 72.004 || $lon > 137.8347 || $lat < 0.8293 || $lat > 55.8271;
}
// 使用示例
// $gcjCoord = wgs84ToGcj02(116.404, 39.915); // WGS84转GCJ02
// $wgsCoord = gcj02ToWgs84(116.404, 39.915); // GCJ02转WGS84
百度地图API在CodeIgniter中的实现:
地理编码、全球逆地理编码、坐标系转换
/**
* 百度地图开放平台接口
*/
class Baidumap extends MY_Controller{
public function __construct(){
parent::__construct();
//百度地图配置
define('BAIDUMAP_CONFIG', array(
'ak' => '百度地图AK',
'sk' => '百度地图SK',
'host' => 'https://api.map.baidu.com',
));
}
//计算请求验证的SN值
private function caculateAKSN($sk, $uri, $param, $method = 'GET'){
if($method === 'POST'){
ksort($param);
}
$querystring = http_build_query($param);
return md5(urlencode($uri.'?'.$querystring.$sk));
}
/**
* 地理编码
* 为保证高德、腾讯、百度地图通用,所以获取的是国测局坐标gcj02ll
* https://lbsyun.baidu.com/faq/api?title=webapi/guide/webservice-geocoding-base
*/
public function geocoder(){
$address=trim(G('address'));
if(empty($address))return json(101,'参数address不能为空');
$city=trim(G('city'));
$city OR $city='济南市';
$coord_type=G('coordtype', 'gcj02ll'); //或百度坐标bd09ll
$uri = '/geocoding/v3/';
//构造请求串数组
$param = array(
'address' => $address,
'city' => $city,
'ret_coordtype' => $coord_type,
'output' => 'json',
'ak' => BAIDUMAP_CONFIG['ak'],
);
//调用sn计算函数,默认get请求
$param['sn'] = $this->caculateAKSN(BAIDUMAP_CONFIG['sk'], $uri, $param);
$res=my_curl(BAIDUMAP_CONFIG['host'].$uri,'GET',$param);
$res=json_decode($res,true);
$res['result']['location']['lng']=(string)$res['result']['location']['lng'];
if(!is_array($res))return json(102,'请求失败,请重试');
if($res['status']==0){
$data=$res['result'];
$data['lon_lat']=$data['location']['lng'].','.$data['location']['lat'];
$data['lat_lon']=$data['location']['lat'].','.$data['location']['lng'];
unset($data['location']);
return json(0,'',$data);
}else{
return json($res['status'],$res['message']);
}
}
/**
* 坐标转换
* 把国测局坐标gcj02ll转为百度坐标
* https://lbsyun.baidu.com/faq/api?title=webapi/guide/changeposition-base
* coord坐标经度在前
$model 转换方式可选值:
1:amap/tencent to bd09ll
2:gps to bd09ll
3:bd09ll to bd09mc
4:bd09mc to bd09ll
5:bd09ll to amap/tencent
6:bd09mc to amap/tencent
*/
public function getconv(){
$coord=str_replace(',',',',trim(G('coord')));
if(!preg_match('/^\d+(\.\d+)?,\d+(\.\d+)?$/',$coord))return json(101,'坐标格式错误');
$model=G('model','1');
$model=is_id($model) ? (int)$model : 1;
$uri = '/geoconv/v2/';
//需转换的源坐标,多组坐标以";"分隔
$param=array(
'coords' => $coord,
'model' => $model,
'output' => 'json',
'ak' => BAIDUMAP_CONFIG['ak'],
);
$param['sn'] = $this->caculateAKSN(BAIDUMAP_CONFIG['sk'], $uri, $param);
$res = my_curl(BAIDUMAP_CONFIG['host'].$uri, 'GET', $param);
//echo $res;
$res = json_decode($res,true);
if(!is_array($res))return json(102,'请求失败,请重试');
if($res['status']!=0){
return json($res['status'], $res['message']);
}
$data=array(
'lon_lat' => $res['result'][0]['x'].','.$res['result'][0]['y'],
'lat_lon' => $res['result'][0]['y'].','.$res['result'][0]['x'],
);
return json(0,'',$data);
}
/**
* 全球逆地理编码
* https://lbsyun.baidu.com/faq/api?title=webapi/guide/webservice-geocoding-abroad-base
* coord坐标纬度在前,格式:纬度,经度
*/
public function reverse_geocoder(){
$coord=str_replace(',',',',trim(G('coord')));
if(empty($coord))return json(101,'参数coord不能为空');
if(!preg_match('/^\d+(\.\d+)?,\d+(\.\d+)?$/',$coord))return json(102,'坐标格式错误');
$coordtype=G('coordtype', 'gcj02ll'); //或百度坐标bd09ll
$uri = '/reverse_geocoding/v3';
$param=array(
'location' => $coord,
'coordtype' => $coordtype,
'extensions_poi' => '1',
'radius' => 50, //poi半径:0-3000米
'region_data_source' => 1, //行政区划数据的来源:1统计局(把开发区作为行政区划返回),2民政部
'entire_poi' => 1,
'sort_strategy' => 'distance',
//'poi_types' => '交通设施|公交线路|铁路',
'output' => 'json',
'ak' => BAIDUMAP_CONFIG['ak'],
);
//printr($param);
$param['sn'] = $this->caculateAKSN(BAIDUMAP_CONFIG['sk'], $uri, $param);
$res = my_curl(BAIDUMAP_CONFIG['host'].$uri, 'GET', $param);
$res = json_decode($res,true);
if($res['status']!=0){
return json($res['status'], $res['message']);
}
$result=$res['result'];
$data=array(
'formatted_address' => $result['formatted_address'],
'formatted_address_poi' => $result['formatted_address_poi'],
'addressComponent' => $result['addressComponent'],
);
json(0,'',$data);
}
}
layui表单中label宽度自适应
@media(min-width:451px){
.layui-form-item{display:flex;align-items:center;}
.layui-form-label{flex:0 0 auto;width:auto !important;min-width:120px;}
.layui-form-pane .layui-input-block{flex:1;margin-left:-1px;}
}
效果如下图:

