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 @@
+
+
+
+
+
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 @@
+
+
+
+
+
文档简易管理
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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 - 众产全栈开发框架