diff --git a/.gitignore b/.gitignore index acb9821..89e6cac 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ # Dependency directories (remove the comment below to include it) 资料/* +web/ud/docs/* web/ud/2025/* web/ud/2026/* web/ud/2027/* diff --git a/web/admin/demo/dyn/mail.html b/web/admin/demo/dyn/mail.html new file mode 100644 index 0000000..aa94fda --- /dev/null +++ b/web/admin/demo/dyn/mail.html @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+ + + + + + + \ No newline at end of file diff --git a/web/admin/demo/dyn/mail.php b/web/admin/demo/dyn/mail.php new file mode 100644 index 0000000..4bd48fa --- /dev/null +++ b/web/admin/demo/dyn/mail.php @@ -0,0 +1,36 @@ +smtp_server = $post->get('smtpserver'); + $mail->smtp_port = $post->getint('smtpport'); + $mail->user = $post->get('user'); + $mail->pass = $post->get('pass'); + $param = array(); + $param['mailto'] = $post->get('mailto'); + $param['title'] = $post->get('title'); + $param['content'] = $post->get('content','','all'); + $retmail = $mail->sendmail($param); + clog($mail->log); + if(is_string($retmail)) + return errjson($retmail); + return succjson(); + } + public static function json_mailrecv() { + $post = new \ciy\post(); + $mail = new \ciy\imap(); + $mail->imap_server = $post->get('imapserver'); + $mail->user = $post->get('user'); + $mail->pass = $post->get('pass'); + $lastuid = $post->getint('lastuid'); + $retmail = $mail->recvmail($lastuid); + clog($mail->log); + if(is_string($retmail)) + return errjson($retmail); + return succjson($retmail); + } +} diff --git a/web/admin/demo/index.html b/web/admin/demo/index.html index bffa8b3..f21ff42 100644 --- a/web/admin/demo/index.html +++ b/web/admin/demo/index.html @@ -159,6 +159,10 @@ proxy prop Proxy响应式示例。 +
+ mail + Mail收发邮件。 +
deepseek DeepSeek接口。 diff --git a/web/docs/components/treemenu.js b/web/docs/components/treemenu.js new file mode 100644 index 0000000..bb34fac --- /dev/null +++ b/web/docs/components/treemenu.js @@ -0,0 +1,75 @@ +const CiyTreemenu = { + name: 'ciy-treemenu', + template: ` +
+ +
+ `, + + props: { + treeData: { + type: Array, + required: true, + default: () => [] + } + }, + beforeCreate() { + console.log('beforeCreate: 实例初始化之后,数据观测和事件配置之前被调用'); + }, + created() { + console.log('created: 实例创建完成后被调用,已完成数据观测、属性和方法的运算',this.treeData); + }, + beforeMount() { + console.log('beforeMount: 挂载开始之前被调用,相关的render函数首次被调用'); + }, + mounted() { + console.log('mounted: 实例挂载完成后调用,此时DOM已经渲染', this.$el); + }, + beforeUpdate() { + console.log('beforeUpdate: 数据更新时调用,发生在虚拟DOM重新渲染和打补丁之前'); + }, + updated() { + console.log('updated: 数据更改导致的虚拟DOM重新渲染和打补丁后调用'); + }, + beforeUnmount() { + console.log('beforeUnmount: 实例销毁之前调用,此时实例仍然完全可用'); + }, + unmounted() { + console.log('unmounted: 实例销毁后调用,所有指令都已解绑,所有事件监听器都已移除'); + }, + activated() { + console.log('activated: 被keep-alive缓存的组件激活时调用'); + }, + deactivated() { + console.log('deactivated: 被keep-alive缓存的组件停用时调用'); + }, + errorCaptured(err, instance, info) { + console.log('errorCaptured: 捕获一个来自后代组件的错误时被调用'); + console.error('Error:', err); + console.log('Vue instance:', instance); + console.log('Error info:', info); + // 可以阻止错误继续向上传播 + return false; + }, + renderTracked({ key, target, type }) { + // console.log('renderTracked: 跟踪虚拟DOM重新渲染时调用'); + // console.log(`操作类型: ${type}, 目标: ${target}, 键: ${key}`); + }, + renderTriggered({ key, target, type }) { + // console.log('renderTriggered: 虚拟DOM重新渲染被触发时调用'); + // console.log(`操作类型: ${type}, 目标: ${target}, 键: ${key}`); + }, + methods: { + selectNode(node) { + this.$emit('node-selected', node); + } + } +}; \ No newline at end of file diff --git a/web/docs/index.html b/web/docs/index.html new file mode 100644 index 0000000..17b5570 --- /dev/null +++ b/web/docs/index.html @@ -0,0 +1,220 @@ + + + + + + Ciyon Docs - 众产全栈开发框架 + + + + + + + + + + + +
+
+
Ciyon Docs - 众产全栈开发框架
+ +
+
+
+ +
+
+
+
+
+
+ + +
+
+
+
+ +
+
+ + + + + + + + + \ No newline at end of file diff --git a/web/docs/index.php b/web/docs/index.php new file mode 100644 index 0000000..99f7d19 --- /dev/null +++ b/web/docs/index.php @@ -0,0 +1,15 @@ +where('isuse', 1)->order('csort desc,id'); + $ret['menu'] = $db->get($csql); + if ($ret['menu'] === false) + return errjson('菜单获取失败:' . $db->error); + return succjson($ret); + } +} diff --git a/web/docs/manage.html b/web/docs/manage.html new file mode 100644 index 0000000..fb72dbd --- /dev/null +++ b/web/docs/manage.html @@ -0,0 +1,356 @@ + + + + + 文档简易管理 + + + + + + + + +
+ +
+
Loading...
+
+
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/web/docs/manage.php b/web/docs/manage.php new file mode 100644 index 0000000..f40e492 --- /dev/null +++ b/web/docs/manage.php @@ -0,0 +1,226 @@ +get('query'); + $csql = new \ciy\sql('doc_help'); + $csql->order('csort desc,id'); + $rows = $db->get($csql); + + $ret = array('list' => $rows); + if ($post->getbool('field')) { + $field = array(); + $fshow = $db->getfield($field, 'doc_help'); + $fshow = fieldadd($fshow, $field, -1, '_btn', '操作'); + $field['csort']['thwidth'] = '5em'; + $ret['field'] = $field; + $ret['fshow'] = $fshow; + } + if ($post->getbool('once')) { + $ret['once'] = array(); + $input = array(); + $input[] = array( + 'type' => 'input', + 'form' => 'name', + 'name' => '标题', + 'prop' => ' style="width:8em;"' + ); + $ret['once']['input'] = $input; + } + return succjson($ret); + } + + public static function json_update() { + global $db; + $post = new \ciy\post(); + if (!self::verify($post->get('pant'))) + return errjson('您未被授权操作'); + $updata = array(); + $id = $post->getint('id'); + if($id < 10) + return errjson('不能操作'); + $name = $post->get('name'); + if ($name == '') + return errjson('请填写标题'); + $csort = $post->getint('csort'); + $isuse = $post->getint('isuse'); + $csql = new \ciy\sql('doc_help'); + $csql->where('id', $id); + $datarow = $db->getone($csql); + if (!is_array($datarow)) + return errjson('数据不存在'); + + try { + $db->begin(); + $updata = array(); + $updata['name'] = $name; + $updata['isuse'] = $isuse; + $updata['csort'] = $csort; + $csql = new \ciy\sql('doc_help'); + $csql->where('id', $id); + if ($db->update($csql, $updata) === false) + throw new \Exception('更新失败:' . $db->error); + $updata['id'] = $id; + $db->commit(); + } catch (\Exception $ex) { + $db->rollback(); + return errjson($ex->getMessage()); + } + return succjson(); + } + public static function json_del() { + global $db; + $rsuser = verifyfast(); + return errjson('功能暂未开放'); + + if (nopower($db, $rsuser['id'], 'p903d')) + return errjson('您未被授权操作'); + $post = new \ciy\post(); + $ids = $post->get('ids'); + if (empty($ids)) + return errjson('请选择至少一条'); + $csql = new \ciy\sql('doc_help'); + $csql->where('id in', $ids); + $rows = $db->get($csql); + $vids = array(); + try { + $db->begin(); + foreach ($rows as $row) { + $delid = $row['id']; + if ($delid >= 10) { + delcheck($db, $delid, 'doc_help', 'upid', '子菜单'); + } + delme($db, $delid, 'doc_help'); + savelogdb($db, $rsuser['id'], 'doc_help', $row, null); + $vids[] = $delid; + } + $db->commit(); + } catch (\Exception $ex) { + $db->rollback(); + return errjson($ex->getMessage()); + } + $ret['ids'] = $vids; + return succjson($ret); + } + public static function json_modifyupid() { + global $db; + $post = new \ciy\post(); + if (!self::verify($post->get('pant'))) + return errjson('您未被授权操作'); + $id = $post->getint('id'); + if($id < 10) + return errjson('不能操作'); + $newupid = $post->getint('newupid'); + $csql = new \ciy\sql('doc_help'); + $csql->where('id', $id); + $datarow = $db->getone($csql); + if (!is_array($datarow)) + return errjson('数据不存在'); + try { + $db->begin(); + $updata = array(); + $updata['upid'] = $newupid; + $csql = new \ciy\sql('doc_help'); + $csql->where('id', $id); + if ($db->update($csql, $updata) === false) + throw new \Exception('更新id失败:' . $db->error); + $updata['id'] = $id; + $db->commit(); + } catch (\Exception $ex) { + $db->rollback(); + return errjson($ex->getMessage()); + } + return succjson(); + } + public static function json_multiadd() { + global $db; + $post = new \ciy\post(); + if (!self::verify($post->get('pant'))) + return errjson('您未被授权操作'); + $upid = $post->getint('upid'); + $multi = explode("\n", $post->get('multi')); + + $cnt = 0; + try { + $db->begin(); + foreach ($multi as $m) { + if (empty(trim($m))) + continue; + $ms = explode('~', $m); + $name = trim($ms[0]); + if (empty($name)) + continue; + $updata = array(); + $updata['name'] = $name; + if (count($ms) > 1) + $updata['url'] = trim($ms[1]); + if (count($ms) > 2) + $updata['pow'] = trim($ms[2]); + $updata['isuse'] = 1; + $updata['upid'] = $upid; + $updata['csort'] = 10; + $updata['uptimes'] = 0; + $csql = new \ciy\sql('doc_help'); + if ($db->insert($csql, $updata) === false) + throw new \Exception('操作数据库失败.' . $db->error); + $updata['id'] = $db->insert_id(); + $cnt++; + } + $db->commit(); + } catch (\Exception $ex) { + $db->rollback(); + return errjson($ex->getMessage()); + } + if ($cnt == 0) + return errjson('没有任何新增'); + $updata = array(); + $updata['url'] = ''; + $updata['pow'] = ''; + $csql = new \ciy\sql('doc_help'); + $csql->where('id', $upid); + $db->update($csql, $updata); + return succjson(); + } + public static function json_uptxt() { + global $db; + $post = new \ciy\post(); + if (!self::verify($post->get('pant'))) + return errjson('您未被授权操作'); + $updata = array(); + $id = $post->getint('id'); + $content = $post->get('content','','all'); + $csql = new \ciy\sql('doc_help'); + $csql->where('id', $id); + $datarow = $db->getone($csql); + if (!is_array($datarow)) + return errjson('数据不存在'); + $uptimes = time(); + try { + $db->begin(); + $updata = array(); + $updata['uptimes'] = $uptimes; + $csql = new \ciy\sql('doc_help'); + $csql->where('id', $id); + if ($db->update($csql, $updata) === false) + throw new \Exception('更新失败:' . $db->error); + $updata['id'] = $id; + $db->commit(); + } catch (\Exception $ex) { + $db->rollback(); + return errjson($ex->getMessage()); + } + file_put_contents(PATH_WEB . 'ud/docs/' . $id . '_' . $uptimes . '.txt', $content); + $ret['uptimes'] = $uptimes; + return succjson($ret); + } +} diff --git a/web/docs/upload.php b/web/docs/upload.php new file mode 100644 index 0000000..019dd95 --- /dev/null +++ b/web/docs/upload.php @@ -0,0 +1,125 @@ + 0) + return errjson(\ciy\upload::UploadError($file['error'])); + list($name, $extfile) = \ciy\upload::Fileext($path); + if ($uploadcfg['checkext'] == 'exts') { + if (!in_array($extfile, $uploadcfg['exts'])) + return errjson("不允许上传{$extfile}类型文件"); + } else { + if (in_array($extfile, $uploadcfg['noexts'])) + return errjson("禁止上传{$extfile}类型文件"); + } + $ret = \ciy\upload::SaveUploadFile($path, $file, $rep == 'true'); + if (is_array($ret)) + return succjson($ret); + return errjson($ret); + } + public static function json_yunsync() { + if (count($_FILES) == 0) + return errjson('没有文件上传'); + $file = reset($_FILES); + if ($file['error'] > 0) + return errjson('上传参数出错:' . $file['error']); + //上传临时文件,通过http put 上传到s3 + $post = new \ciy\post(); + $headers = json_decode($post->get('headers'), true); + $url = $post->get('url'); + $http = new \ciy\http(); + foreach($headers as $key => $value){ + $http->set_header($key,$value); + } + $http->set_method('PUT'); + $http->upfile($url, $file['tmp_name']); + $statcode = $http->get_statcode(); + if($statcode == 200) + return succjson(); + $data = $http->get_data(); + $ind = strpos($data,'error:'); + if($ind !== false) + return errjson(substr($data, $ind + 6)); + return errjson('code[' . $statcode . ']'); + } + public static function json_s3() { + //根据token的ABC决定,用哪个key,包含access/key/region/bucket/endpoint + //存到目录和文件,由js决定,ud/xxx/xxx.jpg + $path = get('pathfile'); // s0/2/2024/0913/demo/65631_7101.jpg + $storselect = get('storselect'); // A + $cfg = webini('s3' . $storselect); + if(is_string($cfg)) + return errjson($cfg); + $objectKey = 'ud/' . $path; + $sha256 = 'UNSIGNED-PAYLOAD'; + + $zdate = gmdate('Ymd\THis\Z'); + $shortDate = substr($zdate, 0, 8); + + $dateKey = hash_hmac('sha256', $shortDate, 'AWS4' . $cfg['secret'], true); + + $regionKey = hash_hmac('sha256', $cfg['region'], $dateKey, true); + $serviceKey = hash_hmac('sha256', 's3', $regionKey, true); + $signingKey = hash_hmac('sha256', 'aws4_request', $serviceKey, true); + + $canonicalUri = '/' . $cfg['bucket'] . '/' . $objectKey; + $canonicalQueryString = ''; + $canonicalHeaders = 'host:' . $cfg['endpoint'] . "\n" . + 'x-amz-acl:' . $cfg['acl'] . "\n" . + 'x-amz-content-sha256:' . $sha256 . "\n" . + 'x-amz-date:' . $zdate . "\n"; + $signedHeaders = 'host;x-amz-acl;x-amz-content-sha256;x-amz-date'; + $canonicalRequest = 'PUT' . "\n" . + $canonicalUri . "\n" . + $canonicalQueryString . "\n" . + $canonicalHeaders . "\n" . + $signedHeaders . "\n" . + $sha256; + + $stringToSign = 'AWS4-HMAC-SHA256' . "\n" . + $zdate . "\n" . + $shortDate . '/' . $cfg['region'] . '/s3/aws4_request' . "\n" . + hash('sha256', $canonicalRequest); + + $signature = hash_hmac('sha256', $stringToSign, $signingKey); + + $authorizationHeader = 'AWS4-HMAC-SHA256 Credential=' . $cfg['access'] . '/' . $shortDate . '/' . $cfg['region'] . '/s3/aws4_request, ' . + 'SignedHeaders=' . $signedHeaders . ', ' . + 'Signature=' . $signature; + + $ret['method'] = 'PUT'; + $ret['url'] = 'https://' . $cfg['endpoint'] . '/' . $cfg['bucket'] . '/' . $objectKey; + $ret['syncurl'] = 'https://up.ciy.cn/up/?json=true&func=yunsync'; + $ret['headers'] = array(); + $ret['headers']['Authorization'] = $authorizationHeader; + $ret['headers']['x-amz-acl'] = $cfg['acl']; + $ret['headers']['x-amz-content-sha256'] = $sha256; + $ret['headers']['x-amz-date'] = $zdate; + //直传后返回url + return succjson($ret); + } +} diff --git a/web/index.html b/web/index.html index 499ac8f..eb8dc46 100644 --- a/web/index.html +++ b/web/index.html @@ -3,7 +3,7 @@ - Ciyon - 众产全栈开发框架 + Ciyon(希央) - 众产全栈开发框架 @@ -102,6 +102,7 @@ Ciyon - 众产全栈开发框架
+ 开发文档 在线演示
@@ -357,20 +358,28 @@