feat: added clien on vue.js and ionic

This commit is contained in:
Arduinum
2026-01-29 15:36:22 +03:00
committed by Arduinum628
parent 1bac371217
commit fc13ed61d4
10 changed files with 140 additions and 54 deletions

View File

@@ -1,11 +1,11 @@
{ {
"name": "client", "name": "kawai-focus",
"version": "0.0.1", "version": "0.0.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "client", "name": "kawai-focus",
"version": "0.0.1", "version": "0.0.1",
"dependencies": { "dependencies": {
"@capacitor/app": "8.0.0", "@capacitor/app": "8.0.0",
@@ -15,6 +15,8 @@
"@capacitor/status-bar": "8.0.0", "@capacitor/status-bar": "8.0.0",
"@ionic/vue": "^8.0.0", "@ionic/vue": "^8.0.0",
"@ionic/vue-router": "^8.0.0", "@ionic/vue-router": "^8.0.0",
"@tauri-apps/api": "^2.9.1",
"@tauri-apps/plugin-sql": "^2.3.1",
"ionicons": "^7.0.0", "ionicons": "^7.0.0",
"vue": "^3.3.0", "vue": "^3.3.0",
"vue-router": "^4.2.0" "vue-router": "^4.2.0"
@@ -3143,6 +3145,25 @@
} }
} }
}, },
"node_modules/@tauri-apps/api": {
"version": "2.9.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/api/-/api-2.9.1.tgz",
"integrity": "sha512-IGlhP6EivjXHepbBic618GOmiWe4URJiIeZFlB7x3czM0yDHHYviH1Xvoiv4FefdkQtn6v7TuwWCRfOGdnVUGw==",
"license": "Apache-2.0 OR MIT",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/tauri"
}
},
"node_modules/@tauri-apps/plugin-sql": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/@tauri-apps/plugin-sql/-/plugin-sql-2.3.1.tgz",
"integrity": "sha512-iNgHnFIR+jRkx9INKVKepzMlxXtNkJUaWuhagFjT4dOttPaNyRnVHgwTjpqZhyVjiklDh2UdEPAJkQKiCPAekw==",
"license": "MIT OR Apache-2.0",
"dependencies": {
"@tauri-apps/api": "^2.8.0"
}
},
"node_modules/@tootallnate/once": { "node_modules/@tootallnate/once": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz",

View File

@@ -5,7 +5,7 @@
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "vue-tsc && vite build", "build": "vite build",
"preview": "vite preview", "preview": "vite preview",
"test:e2e": "cypress run", "test:e2e": "cypress run",
"test:unit": "vitest", "test:unit": "vitest",
@@ -19,6 +19,8 @@
"@capacitor/status-bar": "8.0.0", "@capacitor/status-bar": "8.0.0",
"@ionic/vue": "^8.0.0", "@ionic/vue": "^8.0.0",
"@ionic/vue-router": "^8.0.0", "@ionic/vue-router": "^8.0.0",
"@tauri-apps/api": "^2.9.1",
"@tauri-apps/plugin-sql": "^2.3.1",
"ionicons": "^7.0.0", "ionicons": "^7.0.0",
"vue": "^3.3.0", "vue": "^3.3.0",
"vue-router": "^4.2.0" "vue-router": "^4.2.0"

View File

@@ -4,14 +4,6 @@
</ion-app> </ion-app>
</template> </template>
<script> <script setup>
import { IonApp, IonRouterOutlet } from '@ionic/vue'; import { IonApp, IonRouterOutlet } from '@ionic/vue'
export default {
name: 'App',
components: {
IonApp,
IonRouterOutlet
}
};
</script> </script>

8
client/src/config.js Normal file
View File

@@ -0,0 +1,8 @@
import { appLocalDataDir } from '@tauri-apps/api/path';
export async function getDB_URL() {
// Функция верёнт путь до бд
const appDir = await appLocalDataDir();
return `sqlite:${appDir}/timer.db`;
}

View File

@@ -0,0 +1,10 @@
import { getDb } from "../initDb";
import { SELECT_TIMERS } from "../dml/timerDML";
export async function getTimers() {
// Функция для получения списка таймеров
const db = await getDb();
return await db.select(SELECT_TIMERS);
}

View File

@@ -0,0 +1,11 @@
export const CREATE_TIMER = `
PRAGMA foreign_keys=ON;
CREATE TABLE IF NOT EXISTS timer (
title VARCHAR(200) NOT NULL,
pomodoro_time INTEGER NOT NULL,
break_time INTEGER NOT NULL,
break_long_time INTEGER NOT NULL,
count_pomodoro INTEGER NOT NULL,
id INTEGER NOT NULL,
PRIMARY KEY (id)
);`

View File

@@ -0,0 +1,6 @@
export const SELECT_TIMERS = 'SELECT id, title, pomodoro_time, count_pomodoro FROM timer ORDER BY id DESC'
export const COUNT_TIMERS = 'SELECT COUNT(*) as cnt FROM timer'
export const INSERT_SEED_DB = `
INSERT INTO timer (title, pomodoro_time, break_time, break_long_time, count_pomodoro) VALUES
('Timer mini example', 10, 3, 15, 2), ('Timer max example', 90, 10, 40, 8)
`

26
client/src/db/initDb.js Normal file
View File

@@ -0,0 +1,26 @@
import Database from '@tauri-apps/plugin-sql';
import { CREATE_TIMER } from './ddl/timerDDL';
import { getDB_URL } from '../config';
import { seedDb } from './seed';
let dbPromise = null;
export async function getDb() {
// Функция для получения подключения к базе данных
if (!dbPromise) {
dbPromise = (async () => {
try {
const dbUrl = await getDB_URL();
const db = await Database.load(dbUrl);
await db.execute(CREATE_TIMER);
await seedDb(db);
return db;
} catch (error) {
console.error('Ошибка инициализации базы данных', error);
throw error;
}
})();
}
return await dbPromise; // await для консистентности
}

11
client/src/db/seed.js Normal file
View File

@@ -0,0 +1,11 @@
import { INSERT_SEED_DB, COUNT_TIMERS } from './dml/timerDML'
export async function seedDb(db) {
// Функция для заполнения бд данными
const count = await db.select(COUNT_TIMERS);
if (count[0].cnt === 0) {
await db.execute(INSERT_SEED_DB);
}
}

View File

@@ -8,14 +8,53 @@ import {
trashOutline trashOutline
} from 'ionicons/icons'; } from 'ionicons/icons';
import { ref, onMounted } from 'vue';
import { getTimers } from '../../db/crud/timerCrud';
export default { export default {
name: 'TimersList', name: 'TimersList',
components: { components: {
IonIcon, IonIcon,
}, },
setup() { setup() {
// Возвращаем иконки, чтобы они были доступны в шаблоне const timers = ref([]);
const loading = ref(true);
const error = ref(null);
const expandedId = ref(null);
const loadTimers = async () => {
loading.value = true;
error.value = null;
try {
const result = await getTimers();
timers.value = result;
} catch (err) {
error.value = err.message || 'Ошибка загрузки таймеров';
} finally {
loading.value = false;
}
};
const toggleExpand = (id) => {
expandedId.value = expandedId.value === id ? null : id;
};
onMounted(() => {
loadTimers();
});
return { return {
// состояние
timers,
loading,
error,
expandedId,
// методы
toggleExpand,
// иконки
timerOutline, timerOutline,
chevronUp, chevronUp,
chevronDown, chevronDown,
@@ -24,44 +63,4 @@ export default {
trashOutline, trashOutline,
}; };
}, },
data() {
return {
timers: [],
expandedId: null,
loading: true,
error: null,
apiUrl: 'http://127.0.0.1:8090/api/timers'
};
},
mounted() {
this.fetchTimers();
},
methods: {
async fetchTimers() {
try {
this.loading = true;
this.error = null;
// Для Tauri invoke (раскомментировать при необходимости)
// const { invoke } = window.__TAURI__.tauri;
// this.timers = await invoke('list_timers');
const response = await fetch(`${this.apiUrl}/`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
this.timers = await response.json();
this.loading = false;
} catch (err) {
this.error = `Ошибка загрузки таймеров: ${err.message}`;
this.loading = false;
console.error('Fetch error:', err);
}
},
toggleExpand(timerId) {
this.expandedId = this.expandedId === timerId ? null : timerId;
}
},
}; };