goo blog サービス終了のお知らせ 

Re:SALOON & VBA

しばらくは、過去BBSの倉庫、および
作成した EXCEL VBA の置き場(公開)として

Nuxt.js/MySql版 汎用テーブル照会

2022年08月07日 14時44分40秒 | Node.js他(Python)

来週辺りから、盆休みですが、コロナ禍蔓延中でもあり、猛暑でもあり
ずっと家にいるのかなと思います。リモートワーク中なので、今もそうですが、ずっと椅子の上、姿勢は同じ。
休日は、ただ仕事してないだけです。
で、何かないかと・・・、ああそうだ・・・折角、憶えたNuxtjsを忘れてしまわないようにと・・・
(ボーっとしてにいると無価値存在と自己を責めてしまいがち・・・困った性癖です!)

HTAで作成した、HTA/MySQL版 テーブル一覧を、Nuxt.js で作成してみました。
登録されているテーブルを、画面の作り込みなしで、参照・表示します。
難点は、項目の表示幅が、アジャスト出来ていないことと、
javascript なので日付が、時刻まで表示されてしまうこと(グリニッジ標準時で)
HTA版は、更新機能を追加しましたが、こっちは考えていません。
(プライマリーキーの扱いが難しいので、oracleならROWIDを使うんですが・・・)



【前提】
・windows
・node.js, npm はインストール済

【バックエンド】 仮にホームディレクトリは、「api-nuxt-mytable」とする。<== 任意です。
・ターミナル(コマンドプロンプト、管理者で起動)
$ mkdir api-nuxt-mytable  <== 仮(任意です、お好きに)
$ cd api-nuxt-mytable    <== 仮
$ npm init
$ npm install express
$ npm install mysql
$ mkdir api
$ cd api

■/api/index.js を作成
const express = require('express'); // expressを利用することを定義
const app = express();        // expressをappと定義
const mysql = require('mysql');   // MySQLを利用する
const connection = mysql.createConnection({ // 以下、各自のMySQLへの接続情報を書く
 host   : 'localhost',
 user   : '(MySQLの接続ユーザー)', // 環境に合わせて変更する
 password : '(〃の接続パスワード)',  // 同上
 database : '(〃のデータベース名)'  // 同上
});
app.get('/', function (req, res) { // app.get...(expressの構文)、req=request。 res=response
 res.set({ 'Access-Control-Allow-Origin': '*' }); // この記載により、※1:CORSを許可する
 connection.query('SELECT TABLE_NAME,TABLE_COMMENT,TABLE_ROWS,CREATE_TIME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = "(スキーマ名)"', function (error, results) {
  if (error) throw error; // エラー処理
  res.send(results);
 });
});
app.get('/recList', function (req, res) { // app.get...(expressの構文)、req=request。 res=response
 const tbl = req.query.tbl;
 console.log('TABLE ID' + tbl);
 const sql = 'SELECT C.COLUMN_COMMENT AS text,C.COLUMN_NAME AS value,' +
  ' CASE WHEN C.CHARACTER_MAXIMUM_LENGTH IS NULL THEN 100' +
  ' WHEN C.CHARACTER_MAXIMUM_LENGTH > 100 THEN 500' +
  ' WHEN C.CHARACTER_MAXIMUM_LENGTH < 13 THEN 100' +
  ' ELSE C.CHARACTER_MAXIMUM_LENGTH * 8 END AS width' +
  ' FROM information_schema.COLUMNS C' +
  ' WHERE C.TABLE_SCHEMA = "(スキーマ名)" AND C.TABLE_NAME = ?';
 res.set({ 'Access-Control-Allow-Origin': '*' }); // この記載により、※1:CORSを許可する
 connection.query(sql, tbl, function (error, results) { // テーブルカラムを取得する
  if (error) throw error; // エラー処理
  res.send(results);
 });
});
app.get('/search', function (req, res) { // app.get...(expressの構文)、req=request。 res=response
 const tbl = req.query.tbl;
 console.log('TABLE ID' + tbl);
 const sql = 'SELECT * FROM ' + tbl;
 res.set({ 'Access-Control-Allow-Origin': '*' }); // この記載により、※1:CORSを許可する
 connection.query(sql, function (error, results) { // テーブルデータを取得する
  if (error) throw error; // エラー処理
  res.send(results);
 });
});
app.listen(5000, function () { // port 5000をlistenする
 console.log('Example app listening on port 5000!'); // console.logによりファイル実行時にコンソールに文字表示させる
});

・ターミナル(コマンドプロンプト)…server起動(停止はCTRL + C)
$ node index.js

【フロントエンド】ホームディレクトリは、今回は「nuxt-mytable-app」とします。<== 任意です。

・ターミナル(コマンドプロンプト、管理者で起動)
$ npx create-nuxt-app nuxt-mytable-app <== ※プロジェクト名は任意

※選択肢は、ほとんど規定値かNone 但し、UI framework: Vuetify.js だけは意識して選択

create-nuxt-app v4.0.0
✨ Generating Nuxt.js project in nuxt-mytable-app
? Project name: nuxt-mytable-app
? Programming language: JavaScript
? Package manager: Npm
? UI framework: Vuetify.js
? Nuxt.js modules: Axios - Promise based HTTP client
? Linting tools: ESLint
? Testing framework: None
? Rendering mode: Universal (SSR / SSG)
? Deployment target: Server (Node.js hosting)
? Development tools: (Press to select, <a> to toggle all, <i> to invert selection)
? Continuous integration: None
? Version control system: Git

🎉 Successfully created project nuxt-mytable-app

 To get started:

  cd nuxt-mytable-app
  npm run dev

 To build & start for production:

  cd nuxt-mytable-app
  npm run build
  npm run start

・上記案内に従って、起動確認(修正前に一旦確認)
 $ cd nuxt-mytable-app <== ※プロジェクト名(今回)
 $ npm run dev

・ブラウザで表示
http://localhost:3000

今回は、vue-json-to-csvという機能を追加します。

 $ npm i vue-json-to-csv

さあ、ここから修正です。
■../pages/tableList.vue を作成し追加します。
 ※↓以下 半角の< と > は、全角の < と > に置換して掲載しています。
--------------------------------------------------
<template>
 <dev>
  <v-row>
   <v-col>
    <v-card-title>
     TABLELIST
     <v-spacer />
     <v-text-field
      v-model="search"
      append-icon="mdi-magnify"
      label="Search"
      single-line
      hide-details
     />
    </v-card-title>
   </v-col>
   <v-col>
    <v-card-actions>
     <v-btn
      class="primary"
      @click="downloadData()"
     >
      CSV
     </v-btn>
    </v-card-actions>
   </v-col>
  </v-row>
  <v-data-table
   :headers="headers"
   :items="lists"
   :search="search"
   item-key="line"
  >
   <template #[`item.TABLE_NAME`]="{ item }">
    <a :href="`http://localhost:3000/recList?tbl=${item.TABLE_NAME}`">
     {{ item.TABLE_NAME }}
    </a>
   </template>
   <template #[`item.CREATE_TIME`]="{ item }">
    {{ item.CREATE_TIME.slice(0,10) }}
   </template>
  </v-data-table>
 </dev>
</template>
<script>
/* eslint-disable no-console */
export default {
 name: 'TableList',
 async asyncData ({ $axios }) {
  try {
   const lists = await $axios.$get('http://localhost:5000')
   return { lists }
  } catch (e) {
   console.log(e.errorCode) // eslint-disable-line no-console
   window.alert(e)
  }
 },
 data () {
  return {
   search: '',
   headers: [
    {
     text: 'テーブルID',
     value: 'TABLE_NAME'
    },
    {
     text: 'テーブル名',
     value: 'TABLE_COMMENT'
    },
    {
     text: '件数',
     value: 'TABLE_ROWS'
    },
    {
     text: '作成日',
     value: 'CREATE_TIME'
    }
   ],
   lists: []
  }
 },
 methods: {
  downloadData () {
   let csv = 'テーブルID,テーブル名,件数,作成日\n'
   this.lists.forEach(function (el) {
    csv += el.TABLE_NAME + ',' + el.TABLE_COMMENT + ',' + el.TABLE_ROWS + ',' + el.CREATE_TIME + '\n'
   })
   const anchor = document.createElement('a')
   anchor.href = 'data:text/csv;charset=utf-8,' + encodeURIComponent(csv)
   anchor.target = '_blank'
   anchor.download = 'TABLE_LIST_' + new Date().toISOString().substr(0, 10) + '.csv'
   anchor.click()
  }
 }
}
</script>
<style>
.v-data-table th {
 background: #8C9EFF;
}
.v-data-table td {
 background: #e0e0e0;
}
.v-data-table tr:nth-child(odd) td {
 background: #f5f5f5;
}
.v-data-table tr:hover td {
 background-color: #eee;
}
</style>
--------------------------------------------------

■../pages/recList.vue を作成し追加します。
 ※↓以下 半角の< と > は、全角の < と > に置換して掲載しています。
--------------------------------------------------
<template>
 <dev>
  <v-row>
   <v-col>
    <v-card-title>
     {{ tblId }}
     <v-spacer />
     <v-text-field
      v-model="search"
      append-icon="mdi-magnify"
      label="Search"
      single-line
      hide-details
     />
    </v-card-title>
   </v-col>
   <v-col>
    <v-card-actions>
     <VueJsonToCsv
      :json-data="lists"
      :csv-title="csvFile"
     >
      <v-btn
       class="primary"
      >
       CSV
      </v-btn>
     </VueJsonToCsv>
        
     <v-btn
      class="primary"
      @click="home()"
     >
      戻る
     </v-btn>
    </v-card-actions>
   </v-col>
  </v-row>
  <v-data-table
   :headers="headers"
   :items="lists"
   :search="search"
   item-key="line"
  />
 </dev>
</template>
<script>
/* eslint-disable no-console */
export default {
 data () {
  return {
   tblId: this.$route.query.tbl,
   search: '',
   headers: [],
   lists: [],
   json_meta: [
    [{
     key: 'charset',
     value: 'utf-8'
    }]
   ],
   inTblId: this.$route.query.tbl,
   csvFile: this.$route.query.tbl + '_' + new Date().toISOString().substr(0, 10)
  }
 },
 created () {
  this.searchDate()
 },
 methods: {
  async searchDate () {
   if (!this.inTblId) {
    window.alert('検索キーが未設定です!')
    return
   }
   try {
    const res = await this.$axios.$get('http://localhost:5000/recList', {
     params: {
      tbl: this.inTblId
     }
    })
    this.headers = res
   } catch (e) {
    console.log(e.errorCode) // eslint-disable-line no-console
    window.alert(e)
   }
   try {
    const res = await this.$axios.$get('http://localhost:5000/search', {
     params: {
      tbl: this.inTblId
     }
    })
    this.lists = res
   } catch (e) {
    console.log(e.errorCode) // eslint-disable-line no-console
    window.alert(e)
   }
  },
  home () {
   this.$router.push('/tableList')
  }
 }
}
</script>
<style>
.v-data-table th {
 background: #8C9EFF;
}
.v-data-table td {
 background: #e0e0e0;
}
.v-data-table tr:nth-child(odd) td {
 background: #f5f5f5;
}
.v-data-table tr:hover td {
 background-color: #eee;
}
</style>
--------------------------------------------------

■..\plugins\vue-json-to-csv.js を以下のように作成する。
--------------------------------------------------
import Vue from 'vue'
import VueJsonToCsv from 'vue-json-to-csv'
Vue.component('VueJsonToCsv', VueJsonToCsv)
--------------------------------------------------

■..\nuxt.config.js の plugins: と vuetify:のthema: 部分を以下のように修正する。
--------------------------------------------------
 plugins: [
   { src: '@/plugins/vue-json-to-csv.js' }
 ],
 vuetify: {
  customVariables: ['~/assets/variables.scss'],
  theme: {
   light: true,
   themes: {
    light: {
     background: '#d0f0c0',
     primary: '#00ced1',
     secondary: '#f08080',
     accent: '#9370db',
     error: '#2f4f4f'
    }
   }
  }
 },
--------------------------------------------------

【起動確認】
・バックエンド $ node index.js を実行した状態で
・フロントエンド
 $ cd nuxt-mytable-app <== ※プロジェクト名(今回)
 $ npm run dev

・ブラウザで表示
http://localhost:3000/tableList

ネット学習(として)の生半可、寄せ集め、理解せずに作成、掲載してます。
こうしたら、もっと簡単で、高機能だよいうのが分かる方(誇りたい方、決めたい方はご遠慮下さい)
ご教授ください。老齢初心者です。

■GITHUB
https://github.com/frontflg/MYTABLE_NUXTJS



最新の画像もっと見る

3 Comments(10/1 コメント投稿終了予定)

コメント日が  古い順  |   新しい順
Unknown (frontflug)
2022-08-13 14:25:06
javascript なので日付が、時刻まで表示されてしまうこと(グリニッジ標準時で)
は、見苦しいので、無理やり置換するという方法で対応しました。
以下を■../pages/recList.vue の this.lists = res の後に入れます。(無理やりです。)
for (const item in this.lists) {
 for (const subItem in this.lists[item]) {
  try {
   const str = this.lists[item][subItem]
   if (str !== null && str.indexOf('T15:00:00.000Z') > 0) {
    const dt = new Date(Date.parse(str))
    const month = ('0' + (dt.getMonth() + 1)).slice(-2)
    const day = ('0' + dt.getDate()).slice(-2)
    this.lists[item][subItem] = dt.getFullYear() + '-' + month + '-' + day
   }
  } catch (e) { } // 握りつぶす
 }
}
返信する
Unknown (frontflug)
2022-08-18 16:53:30
ORACLEも試してみましたが、うまく行きません。
$ npm install oracledb

■/api/index.js の設定部分
const oracledb = require('oracledb'); // 今回はoracleを利用する
const connection = oracledb.getConnection({ // 以下、各自のOracleへの接続情報を書く
 user : '(接続ユーザーID)',
 password : '(接続パスワード)',
 connectString: 'localhost:1521/(スキーマ名)'
});
返信する
Unknown (frontflug)
2022-08-18 16:56:02
ORACLEも試してみましたが、うまく行きません。②
■/api/index.js のSQL部分①
connection.query('SELECT T.TABLE_NAME,C.COMMENTS,T.NUM_ROWS,LAST_ANALYZED FROM ALL_TABLES T LEFT JOIN USER_TAB_COMMENTS C ON T.TABLE_NAME = C.TABLE_NAME WHERE T.OWNER = "TESTUSER" ORDER BY T.OWNER,T.TABLE_NAME', function (error, results) {

■/api/index.js のSQL部分②
const sql = 'SELECT C.COMMENTS AS text,T.COLUMN_NAME AS value,' +
' CASE WHEN T.DATA_TYPE = "DATE" THEN 110' +
' WHEN T.DATA_TYPE = "NUMBER" THEN T.DATA_PRECISION * 4 + 50' +
' WHEN T.DATA_LENGTH IS NULL THEN 100' +
' WHEN T.DATA_LENGTH > 90 THEN 500' +
' WHEN T.DATA_LENGTH < 13 THEN 100' +
' ELSE T.DATA_LENGTH * 5 + 40 END AS width' +
' FROM ALL_TAB_COLUMNS T' +
' LEFT JOIN USER_COL_COMMENTS C' +
' ON T.TABLE_NAME = C.TABLE_NAME' +
' AND T.COLUMN_NAME = C.COLUMN_NAME' +
' WHERE T.TABLE_NAME = ? ORDER BY T.COLUMN_ID';
返信する

post a comment

サービス終了に伴い、10月1日にコメント投稿機能を終了させていただく予定です。
ブログ作成者から承認されるまでコメントは反映されません。