Browse Source

add local models

master
godo 1 month ago
parent
commit
e1d6d4acf0
  1. 2020
      os/package-lock.json
  2. 5
      os/package.json
  3. 4
      os/src-tauri/Cargo.toml
  4. 1
      os/src-tauri/src/lib.rs
  5. 0
      os/src/api/init.ts
  6. 79
      os/src/api/local/cache/index.ts
  7. 13
      os/src/api/local/models/users.ts
  8. 21
      os/src/api/local/orm/db.ts
  9. 18
      os/src/api/local/orm/migration.ts
  10. 213
      os/src/api/local/orm/orm.ts
  11. 0
      os/src/api/local/service/auth.ts
  12. 0
      os/src/api/member/auth.ts
  13. 0
      os/src/api/member/files.ts
  14. 0
      os/src/api/member/knowledge.ts
  15. 0
      os/src/api/member/share.ts
  16. 0
      os/src/api/member/workflow.ts
  17. 79
      os/src/api/net/auth.ts
  18. 250
      os/src/api/net/files.ts
  19. 8
      os/src/api/net/knowledge.ts
  20. 25
      os/src/api/net/share.ts
  21. 53
      os/src/api/net/workflow.ts
  22. 64
      os/src/components/auth/AuthLogin.vue
  23. 2
      os/src/components/auth/EmailLogin.vue
  24. 2
      os/src/components/auth/PhoneLogin.vue
  25. 66
      os/src/components/auth/SetUp.vue
  26. 2
      os/src/components/files/SaveFile.vue
  27. 2
      os/src/components/taskbar/ScreenRecorder.vue
  28. 2
      os/src/components/taskbar/Screenshort.vue
  29. 2
      os/src/components/taskbar/StartMenu.vue
  30. 2
      os/src/components/user/ChooseUser.vue
  31. 2
      os/src/components/windows/Collaboration.vue
  32. 2
      os/src/components/windows/IframeApp.vue
  33. 2
      os/src/components/workbench/worktable/ApplyList.vue
  34. 2
      os/src/components/workbench/worktable/CopyFromMe.vue
  35. 2
      os/src/components/workbench/worktable/CopyToMe.vue
  36. 2
      os/src/components/workbench/worktable/MyApply.vue
  37. 2
      os/src/components/workbench/worktable/MyCheck.vue
  38. 2
      os/src/components/workbench/worktable/MyTask.vue
  39. 2
      os/src/components/workbench/worktable/TaskList.vue
  40. 2
      os/src/stores/desktop.ts
  41. 2
      os/src/stores/dragfiles.ts
  42. 6
      os/src/stores/filesystem.ts
  43. 2
      os/src/stores/login.ts
  44. 4
      os/src/stores/settingsConfig.ts
  45. 3
      os/src/styles/login.scss
  46. 2
      os/src/views/knowledgeChat.vue
  47. 24
      os/uno.config.ts

2020
os/package-lock.json

File diff suppressed because it is too large

5
os/package.json

@ -13,10 +13,12 @@
"build:android": "tauri android build --apk",
"android-init": "pnpm tauri plugin android init",
"build:ios": "tauri ios build --ipa",
"ios-init": "pnpm tauri plugin ios init"
"ios-init": "pnpm tauri plugin ios init",
"migrate": "drizzle-kit generate:sqlite"
},
"dependencies": {
"@element-plus/icons-vue": "^2.1.0",
"@libsql/client": "^0.15.4",
"@tauri-apps/plugin-autostart": "~2",
"@tauri-apps/plugin-dialog": "~2.2.1",
"@tauri-apps/plugin-fs": "~2.2.1",
@ -24,6 +26,7 @@
"@tauri-apps/plugin-opener": "~2.2.6",
"@tauri-apps/plugin-os": "~2.2.1",
"@tauri-apps/plugin-process": "~2.2.1",
"@tauri-apps/plugin-sql": "^2.2.0",
"@tauri-apps/plugin-store": "~2.2.0",
"@tauri-apps/plugin-updater": "~2.7.1",
"@tauri-apps/plugin-upload": "~2.2.1",

4
os/src-tauri/Cargo.toml

@ -38,3 +38,7 @@ tauri-plugin-autostart = "2"
tauri-plugin-single-instance = "2"
tauri-plugin-updater = "2"
tauri-plugin-window-state = "2"
[dependencies.tauri-plugin-sql]
features = ["sqlite"] # or "postgres", or "mysql"
version = "2.0.0"

1
os/src-tauri/src/lib.rs

@ -3,6 +3,7 @@ pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_single_instance::init(|_app, _, _| {
}))
.plugin(tauri_plugin_sql::Builder::default().build())
.plugin(tauri_plugin_window_state::Builder::new().build())
.plugin(tauri_plugin_websocket::init())
.plugin(tauri_plugin_opener::init())

0
os/src/api/init.ts

79
os/src/api/local/cache/index.ts

@ -0,0 +1,79 @@
import { Store } from '@tauri-apps/plugin-store';
// 创建 Store 实例(使用异步方式获取)
let store: Store;
async function getStore(): Promise<Store> {
if (!store) {
store = await Store.load('store.bin');
}
return store;
}
// 缓存默认有效期(单位:毫秒)
const DEFAULT_TTL = 1000 * 60 * 10; // 默认 10 分钟
/**
*
* @param key
* @param value
* @param ttl 使
*/
export async function set<T>(key: string, value: T, ttl?: number): Promise<void> {
const storeInstance = await getStore();
const expireAt = Date.now() + (ttl ?? DEFAULT_TTL);
await storeInstance.set(key, { value, expireAt });
await storeInstance.save(); // 可选:立即保存
}
/**
*
* @param key
* @returns null
*/
export async function get<T>(key: string): Promise<T | null> {
const storeInstance = await getStore();
// 使用 storeInstance.has 做初步存在性检查
const exists = await storeInstance.has(key);
if (!exists) return null;
const entry = await storeInstance.get<{ value: T; expireAt: number }>(key);
if (!entry) return null;
const { value, expireAt } = entry;
if (Date.now() > expireAt) {
await storeInstance.delete(key); // 删除过期缓存
return null;
}
return value;
}
/**
*
* @param key
* @returns true false
*/
export async function has(key: string): Promise<boolean> {
const storeInstance = await getStore();
// 使用 storeInstance.has 做初步存在性检查
const exists = await storeInstance.has(key);
if (!exists) return false;
const entry = await storeInstance.get<{ value: any; expireAt: number }>(key);
if (!entry) return false;
const { expireAt } = entry;
if (Date.now() > expireAt) {
await storeInstance.delete(key); // 删除已过期的键
return false;
}
return true;
}
/**
*
*/
export async function clear(): Promise<void> {
const storeInstance = await getStore();
await storeInstance.clear();
}

13
os/src/api/local/models/users.ts

@ -0,0 +1,13 @@
import { createORM } from '../orm/orm.ts';
interface Users {
id?: number;
username: string;
password: string;
nickname: string;
email: string;
phone: string;
isMaster: boolean;
}
export const userDb = createORM<Users>('users');

21
os/src/api/local/orm/db.ts

@ -0,0 +1,21 @@
// src/api/local/db.ts
import Database from '@tauri-apps/plugin-sql';
import { migrationDatabase } from './migration';
let dbInstance: Database | null = null;
export async function connectDatabase(dbPath: string = 'sqlite:godoos.db'): Promise<void> {
if (!dbInstance) {
dbInstance = await Database.load(dbPath);
console.log('✅ 数据库已连接');
}
}
export async function setupDatabase() {
await connectDatabase();
await migrationDatabase();
}
export function getDatabase(): Database {
if (!dbInstance) {
throw new Error('数据库尚未连接,请先调用 connectDatabase');
}
return dbInstance;
}

18
os/src/api/local/orm/migration.ts

@ -0,0 +1,18 @@
import { getDatabase } from './db';
export async function migrationDatabase(): Promise<void> {
const db = getDatabase();
await db.execute(
`CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
password TEXT NOT NULL,
nickname TEXT,
email TEXT,
phone TEXT,
isMaster INTEGER DEFAULT 0
)`
);
console.log('✅ 用户表已初始化');
}

213
os/src/api/local/orm/orm.ts

@ -0,0 +1,213 @@
// src/api/local/orm/orm.ts
import { getDatabase } from './db';
import Database from '@tauri-apps/plugin-sql';
// const userORM = createORM<{ id: number; name: string; role: string }>('users');
// // 查询并分页
// await userORM.where({ role: 'admin' }).page(1, 10).select();
// // 更新数据
// await userORM.save({ role: 'admin' }).where({ id: 1 }).select();
// // 统计数量
// const total = await userORM.where({ role: 'admin' }).count();
type Model = Record<string, any>;
interface ORM<T extends Model> {
create: (data: T) => Promise<void>;
update: (id: any, data: Partial<T>) => Promise<void>;
save: (data: Partial<T>) => ORMQueryBuilder<T>;
select: () => Promise<T[]>;
findById: (id: any) => Promise<T | null>;
delete: (id: any) => Promise<void>;
where: (conditions: Record<string, any>) => ORMQueryBuilder<T>;
count: () => Promise<number>;
page: (page: number, pageSize: number) => ORMQueryBuilder<T>;
}
interface ORMQueryBuilder<T extends Model> {
where: (conditions: Record<string, any>) => ORMQueryBuilder<T>;
count: () => Promise<number>;
page: (page: number, pageSize: number) => ORMQueryBuilder<T>;
select: () => Promise<T[]>;
}
function createORMQueryBuilder<T extends Model>(
db: Database,
table: string
): ORMQueryBuilder<T> {
let conditions: Record<string, any> = {};
let limit: number | null = null;
let offset: number | null = null;
function buildWhereClause(): { clause: string; values: any[] } {
const clauses = [];
const values = [];
for (const key in conditions) {
if (conditions.hasOwnProperty(key)) {
clauses.push(`${key} = $${values.length + 1}`);
values.push(conditions[key]);
}
}
const whereClause = clauses.length > 0 ? `WHERE ${clauses.join(' AND ')}` : '';
return { clause: whereClause, values };
}
const queryBuilder: ORMQueryBuilder<T> = {
where: (newConditions: Record<string, any>): ORMQueryBuilder<T> => {
conditions = { ...conditions, ...newConditions };
return queryBuilder;
},
count: async (): Promise<number> => {
const { clause, values } = buildWhereClause();
const query = `SELECT COUNT(*) as count FROM ${table} ${clause}`;
const result: any = await db.select(query, values);
return result[0]?.count || 0;
},
page: (page: number, pageSize: number): ORMQueryBuilder<T> => {
const newLimit = pageSize;
const newOffset = (page - 1) * pageSize;
limit = newLimit;
offset = newOffset;
return queryBuilder;
},
select: async (): Promise<T[]> => {
const { clause, values } = buildWhereClause();
let limitClause = '';
if (limit !== null && offset !== null) {
limitClause = `LIMIT ${limit} OFFSET ${offset}`;
}
const query = `SELECT * FROM ${table} ${clause} ${limitClause}`;
const result = await db.select(query, values);
return result as T[];
},
};
return queryBuilder;
}
function buildWhereClauseFromConditions(
conditions: Record<string, any>
): { clause: string; values: any[] } {
const clauses = [];
const values = [];
for (const key in conditions) {
if (conditions.hasOwnProperty(key)) {
clauses.push(`${key} = $${values.length + 1}`);
values.push(conditions[key]);
}
}
const whereClause = clauses.length > 0 ? `WHERE ${clauses.join(' AND ')}` : '';
return { clause: whereClause, values };
}
async function executeUpdate<T extends Model>(
db: Database,
table: string,
data: Partial<T>,
conditions: Record<string, any>
): Promise<void> {
const now = new Date().toISOString();
const timestampedData = { ...data, updated_at: now };
const setClause = Object.keys(timestampedData)
.map((key, i) => `${key} = $${i + 1}`)
.join(', ');
const values = Object.values(timestampedData);
const { clause: whereClause, values: whereValues } = buildWhereClauseFromConditions(conditions);
const query = `UPDATE ${table} SET ${setClause} ${whereClause}`;
await db.execute(query, [...values, ...whereValues]);
}
export function createORM<T extends Model>(table: string): ORM<T> {
const db = getDatabase();
const ormInstance: ORM<T> = {
create: async (data: T): Promise<void> => {
const now = new Date().toISOString();
const timestampedData = {
...data,
created_at: now,
updated_at: now,
};
const columns = Object.keys(timestampedData).join(', ');
const placeholders = Object.keys(timestampedData)
.map((_, i) => `$${i + 1}`)
.join(', ');
const values = Object.values(timestampedData);
const query = `INSERT INTO ${table} (${columns}) VALUES (${placeholders})`;
await db.execute(query, values);
},
update: async (id: any, data: Partial<T>): Promise<void> => {
const now = new Date().toISOString();
const timestampedData = {
...data,
updated_at: now,
};
const setClause = Object.keys(timestampedData)
.map((key, i) => `${key} = $${i + 1}`)
.join(', ');
const values = Object.values(timestampedData);
const query = `UPDATE ${table} SET ${setClause} WHERE id = $${values.length + 1}`;
values.push(id);
await db.execute(query, values);
},
save: (data: Partial<T>): ORMQueryBuilder<T> => {
const queryBuilder = createORMQueryBuilder<T>(db, table);
const originalWhere = queryBuilder.where;
queryBuilder.where = (conditions: Record<string, any>): ORMQueryBuilder<T> => {
const updatedQueryBuilder = originalWhere(conditions);
updatedQueryBuilder.select = async (): Promise<T[]> => {
await executeUpdate(db, table, data, conditions);
return [];
};
return updatedQueryBuilder;
};
return queryBuilder;
},
select: (): Promise<T[]> => {
return createORMQueryBuilder<T>(db, table).select();
},
findById: async (id: any): Promise<T | null> => {
const query = `SELECT * FROM ${table} WHERE id = $1`;
const result: any = await db.select(query, [id]);
return result.length > 0 ? (result[0] as T) : null;
},
delete: async (id: any): Promise<void> => {
const query = `DELETE FROM ${table} WHERE id = $1`;
await db.execute(query, [id]);
},
where: (conditions: Record<string, any>): ORMQueryBuilder<T> => {
return createORMQueryBuilder<T>(db, table).where(conditions);
},
count: (): Promise<number> => {
return createORMQueryBuilder<T>(db, table).count();
},
page: (page: number, pageSize: number): ORMQueryBuilder<T> => {
return createORMQueryBuilder<T>(db, table).page(page, pageSize);
},
};
return ormInstance;
}

0
os/src/api/local/service/auth.ts

0
os/src/api/auth.ts → os/src/api/member/auth.ts

0
os/src/api/files.ts → os/src/api/member/files.ts

0
os/src/api/knowledge.ts → os/src/api/member/knowledge.ts

0
os/src/api/share.ts → os/src/api/member/share.ts

0
os/src/api/workflow.ts → os/src/api/member/workflow.ts

79
os/src/api/net/auth.ts

@ -0,0 +1,79 @@
import { loadScript } from '@/utils/load'
import { get, getToken, setToken,post } from '@/utils/request'
import { getClientId } from '@/utils/uuid'
export function loginIn(params: any) {
return fetch('/user/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(res => res.json()).then(res => {
if (res.success) {
setToken(res.data.token)
}
return res
}).catch(err => { throw new Error(err) })
}
export async function logout() {
return post('user/logout', {
method: 'POST',
})
}
export async function isLogin() {
const token = getToken()
if (!token) {
return false
}
const res = await get('user/islogin')
return res.success
}
export async function getDingConf() {
await loadScript(
"https://g.alicdn.com/dingding/h5-dingtalk-login/0.21.0/ddlogin.js"
);
const res = await fetch("user/ding/conf");
return await res.json();
}
export async function getThirdpartyList() {
const result = await fetch("/user/thirdparty/list"
);
if (result.ok) {
const data = await result.json();
if (data.success) return data.data.list;
}
return [];
};
export async function getEmailCode(email: string) {
const data = {
email: email,
client_id: getClientId(),
}
const res = await fetch('/user/emailcode', {
method: 'POST',
body: JSON.stringify(data),
})
return await res.json()
}
export async function getSmsCode(phone: string) {
const data = {
phone: phone,
client_id: getClientId(),
}
const res = await fetch('/user/smscode', {
method: 'POST',
body: JSON.stringify(data),
})
return await res.json()
}
export async function register(params: any) {
return fetch('/user/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(params)
}).then(res => res.json())
}

250
os/src/api/net/files.ts

@ -0,0 +1,250 @@
import { base64ToBuffer, isBase64 } from '@/utils/file'
import { get, post } from '@/utils/request'
export async function read(path: string, pwd?: string) {
const res = await get(`user/files/read`, { path, pwd })
return res
}
export async function readFile(path: string, pwd?: string) {
const res = await get(`user/files/readfile`, { path, pwd })
return res
}
export async function stat(path: string) {
const res = await get(`user/files/stat`, { path })
return res.data
}
export async function desktop() {
const res = await get(`user/files/desktop`)
if (res && res.success) {
return res.data;
}
return false
}
export async function exists(path: string) {
const res = await get(`user/files/exists`, { path })
return res.data
}
export function mkdir(dirPath: string) {
if (dirPath.length < 2 || dirPath.charAt(1) == 'B') {
return false;
}
return post(`user/files/mkdir`, {}, { dirPath }).then(res => res.success)
}
export function rmdir(dirPath: string) {
if (dirPath.length < 3) {
return false;
}
const ext = dirPath.split('.').pop();
if (ext == 'exe') {
return false;
}
return get(`user/files/rmdir`, { dirPath }).then(res => res.success)
}
export function restore(dirPath: string) {
if (dirPath.length < 2) {
return false;
}
return get(`user/files/restore`, { dirPath }).then(res => res.success)
}
export function favorite(path: string) {
if (path.length < 2) {
return false;
}
return get(`user/files/favorite`, { path }).then(res => res.success)
}
export function pwd(path: string, pwd: string) {
if (path.length < 2) {
return false;
}
return get(`user/files/pwd`, { path, pwd }).then(res => res.success)
}
export function unpwd(path: string, pwd: string) {
if (path.length < 2) {
return false;
}
return get(`user/files/unpwd`, { path, pwd }).then(res => res.success)
}
export function rename(oldPath: string, newPath: string) {
if (oldPath.length < 2) {
return false;
}
return get(`user/files/rename`, { oldPath, newPath }).then(res => res.success)
}
export function clear() {
return get(`user/files/clear`).then(res => res.success)
}
export function search(path: string, query: string) {
return get(`user/files/search`, { path, query }).then(res => res.data)
}
export function copy(srcPath: string, dstPath: string) {
if (dstPath.length < 2) {
return false;
}
return get(`user/files/copyfile`, { srcPath, dstPath }).then(res => res.success)
}
export function unlink(path: string) {
if (path.length < 2) {
return false;
}
const ext = path.split('.').pop();
if (ext == 'exe') {
return false;
}
return get(`user/files/unlink`, { path }).then(res => res.success)
}
export function parserFormData(content: any, contentType: any) {
if (!content || content == '') {
return new Blob([], { type: 'text/plain;charset=utf-8' });
}
if (contentType == 'text') {
return new Blob([content], { type: 'text/plain;charset=utf-8' });
}
else if (contentType == 'base64') {
if (content.indexOf(";base64,") > -1) {
const parts = content.split(";base64,");
content = parts[1];
}
content = base64ToBuffer(content);
return new Blob([content]);
}
else if (typeof content === 'object' && content !== null && 'data' in content && Array.isArray(content.data)) {
return new Blob([new Uint8Array(content.data).buffer]);
}
else if (contentType == 'buffer') {
return new Blob([content]);
}
}
export function getFormData(content: any) {
let blobContent: Blob;
//console.log(content)
if (typeof content === 'string') {
if (content) { // 检查 content 是否为空
if (isBase64(content)) {
if (content.indexOf(";base64,") > -1) {
const parts = content.split(";base64,");
content = parts[1];
}
content = base64ToBuffer(content);
blobContent = new Blob([content]);
} else {
//console.log(content)
blobContent = new Blob([content], { type: 'text/plain;charset=utf-8' });
}
} else {
// 处理 content 为空的情况
blobContent = new Blob([], { type: 'text/plain;charset=utf-8' });
}
}
else if (content instanceof Blob) {
// 如果是Blob,直接使用
blobContent = content;
}
else if ('data' in content && Array.isArray(content.data)) {
// 假设data属性是一个字节数组,将其转换为ArrayBuffer
const arrayBuffer = new Uint8Array(content.data).buffer;
//console.log(arrayBuffer)
blobContent = new Blob([arrayBuffer]);
} else if (content instanceof ArrayBuffer) {
// 如果已经是ArrayBuffer,直接使用
blobContent = new Blob([content]);
}
else if (content instanceof Array || content instanceof Object) {
// 如果是数组
blobContent = new Blob([JSON.stringify(content)], { type: 'text/plain;charset=utf-8' });
} else {
throw new Error('Unsupported content format');
}
const formData = new FormData();
formData.append('content', blobContent);
return formData
}
export function writeFile(path: string, data: any, pwd?: string) {
if (path.length < 2) {
return false;
}
const formData = getFormData(data);
if (!formData) {
return false;
}
return post(`user/files/writefile`, formData, { path, pwd }).then(res => {
//console.log(res)
return res.success
})
}
export function appendFile(path: string, data: any) {
const formData = getFormData(data);
if (!formData) {
return false;
}
return post(`user/files/appendfile`, formData, { path }).then(res => res.success)
}
export function zip(path: string, ext: string) {
if (path.length < 2) {
return false;
}
return get(`user/files/zip`, { path, ext }).then(res => res.data)
}
export function unzip(path: string) {
if (path.length < 2) {
return false;
}
return get(`user/files/unzip`, { path }).then(res => res.data)
}
export function isDesktop(path: string) {
const sp = getSp(path)
const arr = path.split(sp)
return arr[1] === 'C' && arr[2] === 'Users' && arr[3] === 'Desktop' && arr.length === 4
}
export function join(path: string, ...paths: string[]) {
const sp = getSp(path)
if (path.endsWith(sp)) {
return path + paths.join(sp)
} else {
return path + sp + paths.join(sp)
}
}
export function basename(path: string): string {
const sp = getSp(path)
return path.split(sp).pop() || path
}
export function dirname(path: string): string {
const sp = getSp(path)
if (path.indexOf(".") > -1) {
return path.split(sp).slice(0, -1).join(sp)
} else {
return path
}
//return path.split(sp).slice(0, -1).join(sp)
}
export function getSp(path: string): string {
if (path.indexOf("\\") > -1) {
return "\\"
} else {
return "/"
}
}
export function getParentPath(path: string): string {
const sp = getSp(path)
const arr = path.split(sp);
arr.pop();
return arr.join(sp);
}
export function getTopPath(path: string) {
const sp = getSp(path)
const arr = path.split(sp);
if (arr[0] == "") {
return arr[1]
} else {
return arr[0]
}
}
export function getExt(path: string) {
return path.split('.').pop() || ''
}

8
os/src/api/net/knowledge.ts

@ -0,0 +1,8 @@
import { get, post } from '@/utils/request'
export function joinknowledge(path: string) {
return get(`user/files/knowledge`, { path })
}
export function askknowledge(data: any) {
return post(`user/files/ask`, data).then((res) => res.data)
}

25
os/src/api/net/share.ts

@ -0,0 +1,25 @@
import { get, post } from '@/utils/request'
export function selectUserList(page: number, nickname: string = "") {
return get('/user/sharelist', { page, nickname }).then(res => res.data)
}
export function searchSelectUsers(ids: any) {
return post('/user/searchuser', { ids }).then(res => res.data)
}
export function shareCreate(data: any) {
return post('/user/files/share', data)
}
// 获取分享用户列表
export function getShareUserList(path: string) {
return get('user/files/collaboration/editusers', { path }).then(res => res.data)
}
// 获取编辑历史记录
export function getEditHistory(path: string, page: string, size: string) {
return get('user/files/collaboration/timeline', { path, page, size }).then(res => res.data)
}
// 还原编辑数据
export function restoreEditData(id: string) {
return post('user/files/collaboration/recover', { id }).then(res => res)
}

53
os/src/api/net/workflow.ts

@ -0,0 +1,53 @@
import { get } from '@/utils/request'
export const getApplyList = (page: number, params?: any) => {
if (params) {
return get('/workflow/datalist?workType=0&knowId=0&limit=10', {
page,
param: 'flowId=' + params,
}).then((res) => res.data)
} else {
return get('/workflow/datalist?workType=0&knowId=0&limit=10', {
page,
}).then((res) => res.data)
}
}
export const getMyApply = () =>
get('/workflow/list?workType=0&knowId=0').then((res) => res.data)
export const getMyTask = () =>
get('/workflow/list?workType=1&knowId=0').then((res) => res.data)
export const getTaskList = (page: number, params?: any) => {
if (params) {
return get('/workflow/datalist?workType=1&knowId=0&limit=10', {
page,
param: 'flowId=' + params,
}).then((res) => res.data)
} else {
return get('/workflow/datalist?workType=1&knowId=0&limit=10', {
page,
}).then((res) => res.data)
}
}
export const getMyCheckList = (page: number) =>
get('/workflow/mychecklist?knowId=0&limit=10', { page }).then(
(res) => res.data
)
// 我的抄送
export const getMyCopyList = (page: number, params: any[]) =>
get('/workflow/getcopytomelist?&limit=10&knowId=0', {
page,
start_date: params[0],
end_date: params[1],
}).then((res) => res.data)
// 历史抄送
export const getCopyFromMeList = (page: number, params: any[]) =>
get('/workflow/getcopyfrommelist?&limit=10&knowId=0', {
page,
start_date: params[0],
end_date: params[1],
}).then((res) => res.data)

64
os/src/components/auth/AuthLogin.vue

@ -1,7 +1,7 @@
<script setup lang="ts">
import { useLoginStore } from "@/stores/login";
import { onMounted, ref } from "vue";
import { List, MapLocation } from "@element-plus/icons-vue";
//import { List, MapLocation } from "@element-plus/icons-vue";
import LdapLogin from "./LdapLogin.vue";
const store = useLoginStore();
@ -21,7 +21,7 @@ const isLock = ref(false);
<el-button type="primary" :icon="MapLocation" circle />
</div> -->
<!-- 顶部欢迎词和 logo -->
<div class="header">
<div class="absolute top-10 left-1/2 -translate-x-1/2 text-center">
<el-avatar size="large" class="logo">
<img src="/logo.png" alt="Logo" />
</el-avatar>
@ -29,7 +29,7 @@ const isLock = ref(false);
</div>
<!-- 登录注册 -->
<div class="login-register" v-if="
<div class="login-register top-45" v-if="
store.thirdPartyLoginMethod !== 'dingding' &&
store.thirdPartyLoginMethod !== 'qyweixin'
">
@ -50,36 +50,38 @@ const isLock = ref(false);
</div>
</div>
<!-- 登录功能 -->
<PasswordLogin v-if="store.thirdPartyLoginMethod === 'password'" />
<SetUp v-if="store.thirdPartyLoginMethod === 'setup'" />
<PhoneLogin v-if="store.thirdPartyLoginMethod === 'phone'" />
<EmailLogin v-if="store.thirdPartyLoginMethod === 'email'" />
<LdapLogin v-if="store.thirdPartyLoginMethod === 'ldap'" />
<div class="qr-code dingding" v-if="store.thirdPartyLoginMethod === 'dingding'">
<div class="qr-code-container" id="dd-qr-code"></div>
</div>
<div class="qr-code-qyweixin" v-if="store.thirdPartyLoginMethod === 'qyweixin'">
<div id="qywechat-qr-code"></div>
</div>
<UserRegister class="register-form" v-if="store.thirdPartyLoginMethod === 'register'" />
<template v-else-if="store.thirdPartyLoginMethod !== 'register'">
<div class="divider" v-if="store.thirdpartyList.length > 0">
<span>第三方登录</span>
<div class="absolute top-62 left-1/2 -translate-x-1/2 text-center w-80">
<PasswordLogin v-if="store.thirdPartyLoginMethod === 'password'" />
<SetUp v-if="store.thirdPartyLoginMethod === 'setup'" />
<PhoneLogin v-if="store.thirdPartyLoginMethod === 'phone'" />
<EmailLogin v-if="store.thirdPartyLoginMethod === 'email'" />
<LdapLogin v-if="store.thirdPartyLoginMethod === 'ldap'" />
<div class="qr-code dingding" v-if="store.thirdPartyLoginMethod === 'dingding'">
<div class="qr-code-container" id="dd-qr-code"></div>
</div>
<div class="third-party-login">
<el-button v-for="platform in store.thirdpartyList" :key="platform.name"
class="third-party-login-button" @click="store.onThirdPartyLogin(platform.name)" :style="{
backgroundColor:
store.thirdPartyLoginMethod ===
platform.name
? '#f2ecec'
: 'transparent',
}">
<img class="third-party-login-icon" :src="platform.icon" />
</el-button>
<div class="qr-code-qyweixin" v-if="store.thirdPartyLoginMethod === 'qyweixin'">
<div id="qywechat-qr-code"></div>
</div>
</template>
<UserRegister v-if="store.thirdPartyLoginMethod === 'register'" />
<template v-else-if="store.thirdPartyLoginMethod !== 'register'">
<div class="divider" v-if="store.thirdpartyList.length > 0">
<span>第三方登录</span>
</div>
<div class="third-party-login">
<el-button v-for="platform in store.thirdpartyList" :key="platform.name"
class="third-party-login-button" @click="store.onThirdPartyLogin(platform.name)" :style="{
backgroundColor:
store.thirdPartyLoginMethod ===
platform.name
? '#f2ecec'
: 'transparent',
}">
<img class="third-party-login-icon" :src="platform.icon" />
</el-button>
</div>
</template>
</div>
</el-card>
<UnLock v-else />
</div>

2
os/src/components/auth/EmailLogin.vue

@ -1,5 +1,5 @@
<script setup lang="ts">
import { getEmailCode } from "@/api/auth"; // API
import { getEmailCode } from "@/api/net/auth"; // API
import { useLoginStore } from "@/stores/login";
import { ElMessage } from "element-plus";
import { ref } from "vue";

2
os/src/components/auth/PhoneLogin.vue

@ -1,5 +1,5 @@
<script setup lang="ts">
import { getSmsCode } from "@/api/auth";
import { getSmsCode } from "@/api/net/auth";
import { useLoginStore } from "@/stores/login";
import { ElMessage } from "element-plus";
import { ref } from "vue";

66
os/src/components/auth/SetUp.vue

@ -1,64 +1,46 @@
<script lang="ts" setup>
import { reactive, ref } from "vue";
import { ref,toRaw } from "vue";
import { errMsg, successMsg } from "@/utils/msg";
import { useSettingsStore } from "@/stores/settings";
const settingsStore = useSettingsStore();
const setForm = ref({
userRole: "person",
storeType: "local",
netUrl: "",
});
const rules = reactive({
username: [
{ required: true, message: "请输入用户名", trigger: "blur" },
{
min: 3,
max: 20,
message: "长度在 3 到 20 个字符",
trigger: "blur",
},
],
password: [
{ required: true, message: "请输入密码", trigger: "blur" },
{
min: 6,
max: 20,
message: "长度在 6 到 20 个字符",
trigger: "blur",
},
],
});
const validateURL = (value: string) => {
const urlPattern = /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})(:[0-9]+)?(\/[\w \.-]*)*\/?$/;
return urlPattern.test(value)
};
const setSave = () => {
const data = toRaw(setForm.value);
//console.log("",data);
if((data.storeType === 'net' || data.userRole === 'member') && !validateURL(data.netUrl)){
errMsg("请输入正确的URL地址!");
return;
}
settingsStore.setConfig('system',data)
successMsg("设置成功!");
};
</script>
<template>
<el-form :model="setForm" :rules="rules" ref="emailLoginFormRef" label-position="left" label-width="0px">
<el-form :model="setForm" ref="formRef" label-position="left" label-width="0px">
<el-form-item label-position="right">
<el-button-group>
<el-button :type="setForm.userRole == 'person' ? 'primary' : ''" @click="setForm.userRole = 'person'" icon="ArrowLeft" round>个人用户</el-button>
<el-button :type="setForm.userRole == 'member' ? 'primary' : ''" @click="setForm.userRole = 'member'" icon="ArrowRight" round>企业用户</el-button>
<el-button :type="setForm.userRole == 'person' ? 'primary' : ''" @click="setForm.userRole = 'person'" icon="UserFilled" round>个人用户</el-button>
<el-button :type="setForm.userRole == 'member' ? 'primary' : ''" @click="setForm.userRole = 'member'" icon="Football" round>企业用户</el-button>
</el-button-group>
</el-form-item>
<el-form-item label-position="right" v-if="setForm.userRole === 'person'">
<el-button-group>
<el-button :type="setForm.storeType == 'local' ? 'primary' : ''" @click="setForm.storeType = 'local'" icon="ArrowLeft" round>本地服务</el-button>
<el-button :type="setForm.storeType == 'net' ? 'primary' : ''" @click="setForm.storeType = 'net'" icon="ArrowRight" round>远程服务</el-button>
<el-button :type="setForm.storeType == 'local' ? 'primary' : ''" @click="setForm.storeType = 'local'" icon="LocationInformation" round>本地服务</el-button>
<el-button :type="setForm.storeType == 'net' ? 'primary' : ''" @click="setForm.storeType = 'net'" icon="Promotion" round>远程服务</el-button>
</el-button-group>
</el-form-item>
<!-- <el-form-item label-position="right">
<el-radio-group v-model="setForm.userRole" aria-label="label position">
<el-radio-button value="person" round>个人用户</el-radio-button>
<el-radio-button value="member">企业用户</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item label-position="right" v-if="setForm.userRole === 'person'">
<el-radio-group v-model="setForm.storeType" aria-label="label position">
<el-radio-button value="local">本地存储</el-radio-button>
<el-radio-button value="brower">浏览器存储</el-radio-button>
<el-radio-button value="net">远程存储</el-radio-button>
</el-radio-group>
</el-form-item> -->
<el-form-item prop="neturl" v-if="setForm.storeType === 'net' || setForm.userRole === 'member'">
<el-input v-model="setForm.netUrl" size="large" placeholder="请输入远程地址" autofocus
prefix-icon="Link"></el-input>
<el-form-item prop="netUrl" v-if="setForm.storeType === 'net' || setForm.userRole === 'member'">
<el-input v-model="setForm.netUrl" size="large" placeholder="请输入远程地址" autofocus prefix-icon="Link"></el-input>
</el-form-item>
<el-form-item class="button-center">
<el-button class="login-button" type="primary" size="large" @click="setSave">保存</el-button>

2
os/src/components/files/SaveFile.vue

@ -27,7 +27,7 @@
</template>
<script lang="ts" setup>
import { join } from "@/api/files";
import { join } from "@/api/net/files";
import { useClickingStore } from "@/stores/clicking";
import { useFileSystemStore } from "@/stores/filesystem";
import { useWindowStore } from "@/stores/window";

2
os/src/components/taskbar/ScreenRecorder.vue

@ -63,7 +63,7 @@
<script setup lang="ts">
import useScreenRecorder from "@/utils/screenRecorder";
import {writeFile} from '@/api/files';
import {writeFile} from '@/api/net/files';
import { successMsg } from "@/utils/msg";
const screenRecorder: any = useScreenRecorder();

2
os/src/components/taskbar/Screenshort.vue

@ -21,7 +21,7 @@
<script setup lang="ts">
import { ref } from "vue";
import {writeFile} from '@/api/files';
import {writeFile} from '@/api/net/files';
const screenshotStatus = ref<boolean>(false);
import { isBase64, base64ToBuffer } from "@/utils/file";
import { successMsg } from "@/utils/msg";

2
os/src/components/taskbar/StartMenu.vue

@ -64,7 +64,7 @@ import { useLoginStore } from '@/stores/login'
import { useDesktopStore } from '@/stores/desktop'
import {dealIcon} from '@/utils/icon'
import { clear } from '@/api/files'
import { clear } from '@/api/net/files'
import { t } from '@/i18n'
import { useRouter } from 'vue-router'
import { confirmMsg } from '@/utils/msg'

2
os/src/components/user/ChooseUser.vue

@ -18,7 +18,7 @@
</el-select>
</template>
<script setup lang="ts">
import { selectUserList, searchSelectUsers } from "@/api/share";
import { selectUserList, searchSelectUsers } from "@/api/net/share";
import { onMounted, ref, watch } from "vue";
import defaultAvatar from '/logo.png';
import { useChatStore } from "@/stores/chat";

2
os/src/components/windows/Collaboration.vue

@ -58,7 +58,7 @@ import {
getEditHistory,
getShareUserList,
restoreEditData,
} from "@/api/share";
} from "@/api/net/share";
import { useFileSystemStore } from "@/stores/filesystem";
import { errMsg, successMsg } from "@/utils/msg";
import { onMounted, ref } from "vue";

2
os/src/components/windows/IframeApp.vue

@ -1,5 +1,5 @@
<script setup lang="ts">
import * as fs from "@/api/files";
import * as fs from "@/api/net/files";
import { getExportType } from "@/router/filemaplist";
import { useAiChatStore } from "@/stores/aichat";
import { useFileSystemStore } from "@/stores/filesystem";

2
os/src/components/workbench/worktable/ApplyList.vue

@ -19,7 +19,7 @@
<script setup lang="ts">
import { onMounted, ref, watch } from 'vue';
import { getApplyList } from '@/api/workflow';
import { getApplyList } from '@/api/net/workflow';
const page = ref(1);
const flowList: any = ref([])
const select: any = ref('')

2
os/src/components/workbench/worktable/CopyFromMe.vue

@ -15,7 +15,7 @@
<script setup lang="ts">
import { ref } from 'vue'
import { getCopyFromMeList } from '@/api/workflow';
import { getCopyFromMeList } from '@/api/net/workflow';
const columns = [
{ prop: 'Id', label: 'ID' },

2
os/src/components/workbench/worktable/CopyToMe.vue

@ -24,7 +24,7 @@
<script setup lang="ts">
import { ref } from 'vue'
import { getMyCopyList } from '@/api/workflow';
import { getMyCopyList } from '@/api/net/workflow';
const columns = [
{ prop: 'Id', label: 'ID' },

2
os/src/components/workbench/worktable/MyApply.vue

@ -24,7 +24,7 @@
</template>
<script setup lang="ts">
import { getMyApply } from '@/api/workflow';
import { getMyApply } from '@/api/net/workflow';
import { onMounted, ref } from 'vue';
const catList: any = ref([])

2
os/src/components/workbench/worktable/MyCheck.vue

@ -10,7 +10,7 @@
<script setup lang="ts">
import { ref, watch } from 'vue'
import { getMyCheckList } from '@/api/workflow'
import { getMyCheckList } from '@/api/net/workflow'
const cardRef = ref()
const props = defineProps<{
reload: boolean

2
os/src/components/workbench/worktable/MyTask.vue

@ -24,7 +24,7 @@
</template>
<script setup lang="ts">
import { getMyTask } from '@/api/workflow';
import { getMyTask } from '@/api/net/workflow';
import { onMounted, ref } from 'vue';
const catList: any = ref([])

2
os/src/components/workbench/worktable/TaskList.vue

@ -18,7 +18,7 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { getTaskList } from '@/api/workflow';
import { getTaskList } from '@/api/net/workflow';
const page = ref(1);
const flowList: any = ref([]);
const select = ref('');

2
os/src/stores/desktop.ts

@ -1,6 +1,6 @@
import { defineStore } from 'pinia'
import { ref, Ref, computed } from 'vue'
import { desktop } from '@/api/files'
import { desktop } from '@/api/net/files'
import { useLoginStore } from './login'
export const useDesktopStore = defineStore('desktop', () => {

2
os/src/stores/dragfiles.ts

@ -1,5 +1,5 @@
import { defineStore } from 'pinia';
import { join } from '@/api/files';
import { join } from '@/api/net/files';
import { useClickingStore } from './clicking';
import { useFileSystemStore } from './filesystem';
import { ref } from 'vue';

6
os/src/stores/filesystem.ts

@ -1,6 +1,6 @@
import * as fs from '@/api/files';
import { joinknowledge } from '@/api/knowledge';
import { shareCreate } from "@/api/share";
import * as fs from '@/api/net/files';
import { joinknowledge } from '@/api/net/knowledge';
import { shareCreate } from "@/api/net/share";
import { eventBus } from '@/interfaces/event';
import { getFileType } from '@/router/filemaplist';
import { errMsg, noticeMsg, promptMsg, promptPwd, successMsg } from '@/utils/msg';

2
os/src/stores/login.ts

@ -1,4 +1,4 @@
import { getThirdpartyList, isLogin, loginIn, logout } from '@/api/auth'
import { getThirdpartyList, isLogin, loginIn, logout } from '@/api/net/auth'
import router from '@/router'
import { useDesktopStore } from '@/stores/desktop'
import { loadScript } from '@/utils/load'

4
os/src/stores/settingsConfig.ts

@ -132,12 +132,12 @@ export const settingsConfig = {
imageList: [bg1, bg2, bg3, bg4, bg5, bg6, bg7, bg8, bg9],
url: bg6,
},
lock : {
lock: {
timeout: 0,
activeTime: 0,
password: ''
},
system : {
system: {
userType: "person",
storeType: "local",
netUrl: "",

3
os/src/styles/login.scss

@ -119,6 +119,9 @@
}
.login-register {
position: absolute;
left:10%;
width: 80%;
display: flex;
justify-content: space-between;
align-items: center;

2
os/src/views/knowledgeChat.vue

@ -7,7 +7,7 @@ import { ElScrollbar } from "element-plus";
import { Vue3Lottie } from "vue3-lottie";
import { isMobileDevice } from "@/utils/device";
import { computed, nextTick, onMounted, ref, watch } from "vue";
import { askknowledge } from "@/api/knowledge";
import { askknowledge } from "@/api/net/knowledge";
const chatStore = useAiChatStore();
const isPadding = ref(false); //

24
os/uno.config.ts

@ -102,20 +102,20 @@ export default defineConfig({
[/^el-color-(\w*)$/, ([_, color]) => ({ color: `var(--el-color-${color})` })],
[/^el-bg-(\w*)$/, ([_, color]) => ({ "background-color": `var(--el-color-${color})` })],
// 文字按钮
// [/^btn-(\w*)$/, ([_, color]) => ({
// "--at-apply": `transition-200 cursor-pointer rounded-4px hover:text-[var(--el-color-${color})]`,
// })],
// [/^btn-(\w*)-text$/, ([_, color]) => ({
// "--at-apply": `transition-200 cursor-pointer rounded-4px hover:text-[var(--el-color-${color})]`,
// })],
[/^btn-(\w*)$/, ([_, color]) => ({
"--at-apply": `transition-200 cursor-pointer rounded-4px hover:text-[var(--el-color-${color})]`,
})],
[/^btn-(\w*)-text$/, ([_, color]) => ({
"--at-apply": `transition-200 cursor-pointer rounded-4px hover:text-[var(--el-color-${color})]`,
})],
// // 文字背景按钮
// [/^btn-(\w*)-bg$/, ([_, color]) => ({
// "--at-apply": `transition-200 cursor-pointer rounded-4px hover:(text-white bg-[var(--el-color-${color})]) `,
// })],
[/^btn-(\w*)-bg$/, ([_, color]) => ({
"--at-apply": `transition-200 cursor-pointer rounded-4px hover:(text-white bg-[var(--el-color-${color})]) `,
})],
// // 文字按钮组
// [/^group-btn-(\w*)$/, ([_, color]) => ({
// "--at-apply": `transition-200 cursor-pointer rounded-4px group-hover:text-[var(--el-color-${color})]`,
// })],
[/^group-btn-(\w*)$/, ([_, color]) => ({
"--at-apply": `transition-200 cursor-pointer rounded-4px group-hover:text-[var(--el-color-${color})]`,
})],
],
theme: {
// ...

Loading…
Cancel
Save